From d7d9a994d522e02f89a227973ee951f59a45980c Mon Sep 17 00:00:00 2001 From: Duncan Sommerville Date: Wed, 15 Jul 2015 18:53:19 -0400 Subject: [PATCH] SAAS-948 - ShowBuilder redesign initial commit --- airtime_mvc/application/Bootstrap.php | 4 +- airtime_mvc/application/configs/ACL.php | 2 + .../controllers/LibraryController.php | 14 + .../controllers/ShowBuilderController.php | 52 + airtime_mvc/application/models/StoredFile.php | 106 ++ .../views/scripts/show-builder/index.phtml | 43 + .../views/scripts/widgets/lib-table.phtml | 10 + airtime_mvc/build/sql/defaultdata.sql | 1 - .../public/css/dropzone/dropzone.min.css | 1 + airtime_mvc/public/css/media_library.css | 1 - airtime_mvc/public/css/showbuilder.css | 4 +- airtime_mvc/public/css/styles.css | 85 +- .../library/events/library_showbuilder.js | 10 +- .../public/js/airtime/library/library-test.js | 978 +++++++++++++++ .../public/js/airtime/library/library.js | 38 +- .../public/js/airtime/showbuilder/builder.js | 6 +- .../js/airtime/showbuilder/builder_test.js | 1112 +++++++++++++++++ .../airtime/showbuilder/main_builder_test.js | 347 +++++ airtime_mvc/public/js/libs/dropzone.min.js | 2 + 19 files changed, 2786 insertions(+), 30 deletions(-) create mode 100644 airtime_mvc/application/controllers/ShowBuilderController.php create mode 100644 airtime_mvc/application/views/scripts/show-builder/index.phtml create mode 100644 airtime_mvc/application/views/scripts/widgets/lib-table.phtml create mode 100644 airtime_mvc/public/css/dropzone/dropzone.min.css create mode 100644 airtime_mvc/public/js/airtime/library/library-test.js create mode 100644 airtime_mvc/public/js/airtime/showbuilder/builder_test.js create mode 100644 airtime_mvc/public/js/airtime/showbuilder/main_builder_test.js create mode 100644 airtime_mvc/public/js/libs/dropzone.min.js diff --git a/airtime_mvc/application/Bootstrap.php b/airtime_mvc/application/Bootstrap.php index 4a5157f1e..f16183157 100644 --- a/airtime_mvc/application/Bootstrap.php +++ b/airtime_mvc/application/Bootstrap.php @@ -130,9 +130,9 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap protected function _initTasks() { /* We need to wrap this here so that we aren't checking when we're running the unit test suite */ - $taskManager = TaskManager::getInstance(); - $taskManager->runTask(AirtimeTask::UPGRADE); // Run the upgrade on each request (if it needs to be run) if (getenv("AIRTIME_UNIT_TEST") != 1) { + $taskManager = TaskManager::getInstance(); + $taskManager->runTask(AirtimeTask::UPGRADE); // Run the upgrade on each request (if it needs to be run) //This will do the upgrade too if it's needed... $taskManager->runTasks(); } diff --git a/airtime_mvc/application/configs/ACL.php b/airtime_mvc/application/configs/ACL.php index 07ca7d822..39bba31ae 100644 --- a/airtime_mvc/application/configs/ACL.php +++ b/airtime_mvc/application/configs/ACL.php @@ -24,6 +24,7 @@ $ccAcl->add(new Zend_Acl_Resource('library')) ->add(new Zend_Acl_Resource('dashboard')) ->add(new Zend_Acl_Resource('preference')) ->add(new Zend_Acl_Resource('showbuilder')) + ->add(new Zend_Acl_Resource('show-builder')) ->add(new Zend_Acl_Resource('playouthistory')) ->add(new Zend_Acl_Resource('playouthistorytemplate')) ->add(new Zend_Acl_Resource('listenerstat')) @@ -49,6 +50,7 @@ $ccAcl->allow('G', 'index') ->allow('G', 'error') ->allow('G', 'user', 'edit-user') ->allow('G', 'showbuilder') + ->allow('G', 'show-builder') ->allow('G', 'api') ->allow('G', 'schedule') ->allow('G', 'dashboard') diff --git a/airtime_mvc/application/controllers/LibraryController.php b/airtime_mvc/application/controllers/LibraryController.php index 2ad032973..d0f7f0f09 100644 --- a/airtime_mvc/application/controllers/LibraryController.php +++ b/airtime_mvc/application/controllers/LibraryController.php @@ -11,6 +11,7 @@ class LibraryController extends Zend_Controller_Action { $ajaxContext = $this->_helper->getHelper('AjaxContext'); $ajaxContext->addActionContext('contents-feed', 'json') + ->addActionContext('contents-feed-test', 'json') ->addActionContext('delete', 'json') ->addActionContext('duplicate', 'json') ->addActionContext('delete-group', 'json') @@ -425,6 +426,19 @@ class LibraryController extends Zend_Controller_Action $this->view->files = SecurityHelper::htmlescape_recursive($r["aaData"]); } + public function contentsFeedTestAction() + { + $params = $this->getRequest()->getParams(); + + # terrible name for the method below. it does not only search files. + $r = Application_Model_StoredFile::searchLibraryFiles($params); + + $this->view->sEcho = $r["sEcho"]; + $this->view->iTotalDisplayRecords = $r["iTotalDisplayRecords"]; + $this->view->iTotalRecords = $r["iTotalRecords"]; + $this->view->files = SecurityHelper::htmlescape_recursive($r["aaData"]); + } + public function editFileMdAction() { $user = Application_Model_User::getCurrentUser(); diff --git a/airtime_mvc/application/controllers/ShowBuilderController.php b/airtime_mvc/application/controllers/ShowBuilderController.php new file mode 100644 index 000000000..c5cd87818 --- /dev/null +++ b/airtime_mvc/application/controllers/ShowBuilderController.php @@ -0,0 +1,52 @@ +getType(); + + $this->view->headScript()->appendScript("localStorage.setItem( 'user-type', '$userType' );"); + $this->view->headScript()->appendScript(Application_Common_GoogleAnalytics::generateGoogleTagManagerDataLayerJavaScript()); + + $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/dataTables.ColVis.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.FixedColumns.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.columnFilter.js?'.$CC_CONFIG['airtime_version'], 'text/javascript'); + + $this->view->headScript()->appendFile($baseUrl.'js/blockui/jquery.blockUI.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->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']); + $this->view->headLink()->appendStylesheet($baseUrl.'css/datatables/css/ColReorder.css?'.$CC_CONFIG['airtime_version']); + $this->view->headScript()->appendFile($baseUrl.'js/airtime/library/library-test.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/airtime/library/events/library_showbuilder.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + + // PLUPLOAD + $this->view->headScript()->appendFile($baseUrl.'js/libs/dropzone.min.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headLink()->appendStylesheet($baseUrl.'css/dropzone/dropzone.min.css?'.$CC_CONFIG['airtime_version']); + + $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_test.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/airtime/showbuilder/main_builder_test.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + + $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']); + + $csrf_namespace = new Zend_Session_Namespace('csrf_namespace'); + $csrf_element = new Zend_Form_Element_Hidden('csrf'); + $csrf_element->setValue($csrf_namespace->authtoken)->setRequired('true')->removeDecorator('HtmlTag')->removeDecorator('Label'); + $this->view->csrf = $csrf_element; + } + +} diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index e975ccd8c..5d92dd54d 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -907,6 +907,112 @@ SQL; return $results; } + public static function searchLibraryFilesTest($datatables) + { + $con = Propel::getConnection(CcFilesPeer::DATABASE_NAME); + $displayColumns = self::getLibraryColumns(); + + $fileSelect = array(); + foreach ($displayColumns as $key) { + if ($key === "id") { + $fileSelect[] = "FILES.id AS $key"; + } elseif ($key === "owner_id") { + $fileSelect[] = "sub.login AS $key"; + } //file length is displayed based on cueout - cuein. + else if ($key === "length") { + $fileSelect[] = "(cueout - cuein)::INTERVAL AS length"; + } elseif ($key === "year") { + $fileSelect[] = "year AS ".$key; + } else { + $fileSelect[] = $key; + } + } + + $fileSelect = "SELECT ". join(",", $fileSelect); + $fileTable = "({$fileSelect} FROM cc_files AS FILES LEFT JOIN cc_subjs AS sub ON (sub.id = FILES.owner_id) WHERE file_exists = 'TRUE' AND hidden='FALSE')"; + $fromTable = $fileTable." AS File"; //need an alias for the table if it's standalone. + + // update is_scheduled to false for tracks that + // have already played out + self::updatePastFilesIsScheduled(); + $results = Application_Model_Datatables::findEntries($con, $displayColumns, $fromTable, $datatables); + + $displayTimezone = new DateTimeZone(Application_Model_Preference::GetUserTimezone()); + $utcTimezone = new DateTimeZone("UTC"); + + foreach ($results['aaData'] as &$row) { + $row['id'] = intval($row['id']); + + //taken from Datatables.php, needs to be cleaned up there. + if (isset($r['ftype'])) { + if ($r['ftype'] == 'playlist') { + $pl = new Application_Model_Playlist($r['id']); + $r['length'] = $pl->getLength(); + } elseif ($r['ftype'] == "block") { + $bl = new Application_Model_Block($r['id']); + $r['bl_type'] = $bl->isStatic() ? 'static' : 'dynamic'; + $r['length'] = $bl->getLength(); + } + } + + if ($row['ftype'] === "audioclip") { + + $cuein_formatter = new LengthFormatter($row["cuein"]); + $row["cuein"] = $cuein_formatter->format(); + + $cueout_formatter = new LengthFormatter($row["cueout"]); + $row["cueout"] = $cueout_formatter->format(); + + $cuein = Application_Common_DateHelper::playlistTimeToSeconds($row["cuein"]); + $cueout = Application_Common_DateHelper::playlistTimeToSeconds($row["cueout"]); + $row_length = Application_Common_DateHelper::secondsToPlaylistTime($cueout - $cuein); + + $formatter = new SamplerateFormatter($row['sample_rate']); + $row['sample_rate'] = $formatter->format(); + + $formatter = new BitrateFormatter($row['bit_rate']); + $row['bit_rate'] = $formatter->format(); + + // for audio preview + $row['audioFile'] = $row['id'].".".pathinfo($row['filepath'], PATHINFO_EXTENSION); + + } + else { + + $row['audioFile'] = $row['id']; + $row_length = $row['length']; + } + + $len_formatter = new LengthFormatter($row_length); + $row['length'] = $len_formatter->format(); + + //convert mtime and utime to localtime + $row['mtime'] = new DateTime($row['mtime'], $utcTimezone); + $row['mtime']->setTimeZone($displayTimezone); + $row['mtime'] = $row['mtime']->format(DEFAULT_TIMESTAMP_FORMAT); + $row['utime'] = new DateTime($row['utime'], $utcTimezone); + $row['utime']->setTimeZone($displayTimezone); + $row['utime'] = $row['utime']->format(DEFAULT_TIMESTAMP_FORMAT); + + //need to convert last played to localtime if it exists. + if (isset($row['lptime'])) { + $row['lptime'] = new DateTime($row['lptime'], $utcTimezone); + $row['lptime']->setTimeZone($displayTimezone); + $row['lptime'] = $row['lptime']->format(DEFAULT_TIMESTAMP_FORMAT); + } + + // we need to initalize the checkbox and image row because we do not retrieve + // any data from the db for these and datatables will complain + $row['checkbox'] = ""; + $row['image'] = ""; + + $type = substr($row['ftype'], 0, 2); + $row['tr_id'] = "{$type}_{$row['id']}"; + } + + return $results; + } + /** * Copy a newly uploaded audio file from its temporary upload directory * on the local disk (like /tmp) over to Airtime's "stor" directory, diff --git a/airtime_mvc/application/views/scripts/show-builder/index.phtml b/airtime_mvc/application/views/scripts/show-builder/index.phtml new file mode 100644 index 000000000..5d4b7abd1 --- /dev/null +++ b/airtime_mvc/application/views/scripts/show-builder/index.phtml @@ -0,0 +1,43 @@ + +
quotaLimitReached) { ?> class="hidden" > + csrf ?> +
+ +
+
+ +
+ +
Files
+
Playlists
+
Smart Blocks
+
Webstreams
+
+ +
+ render('widgets/lib-table.phtml') ?> +
+ +
+
+ sb_form; ?> +
+
+
+dialog ?> diff --git a/airtime_mvc/application/views/scripts/widgets/lib-table.phtml b/airtime_mvc/application/views/scripts/widgets/lib-table.phtml new file mode 100644 index 000000000..894620a71 --- /dev/null +++ b/airtime_mvc/application/views/scripts/widgets/lib-table.phtml @@ -0,0 +1,10 @@ +
+ + + + + +
+ + +
diff --git a/airtime_mvc/build/sql/defaultdata.sql b/airtime_mvc/build/sql/defaultdata.sql index 30fd8d765..bed25b869 100644 --- a/airtime_mvc/build/sql/defaultdata.sql +++ b/airtime_mvc/build/sql/defaultdata.sql @@ -378,7 +378,6 @@ INSERT INTO cc_stream_setting (keyname, value, type) VALUES ('s4_channels', 'ste -- added in 2.5.14 - this can't be set up in Propel's XML schema, so we need to do it here -- Duncan -ALTER TABLE cc_pref ALTER COLUMN subjid SET NULL; ALTER TABLE cc_pref ALTER COLUMN subjid SET DEFAULT NULL; CREATE UNIQUE INDEX cc_pref_key_idx ON cc_pref (keystr) WHERE subjid IS NULL; ANALYZE cc_pref; -- this validates the new partial index diff --git a/airtime_mvc/public/css/dropzone/dropzone.min.css b/airtime_mvc/public/css/dropzone/dropzone.min.css new file mode 100644 index 000000000..d04515e27 --- /dev/null +++ b/airtime_mvc/public/css/dropzone/dropzone.min.css @@ -0,0 +1 @@ +@-webkit-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%, 70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-moz-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%, 70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%, 70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-webkit-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@-moz-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@-webkit-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@-moz-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}.dropzone,.dropzone *{box-sizing:border-box}.dropzone{min-height:150px;border:2px solid rgba(0,0,0,0.3);background:white;padding:20px 20px}.dropzone.dz-clickable{cursor:pointer}.dropzone.dz-clickable *{cursor:default}.dropzone.dz-clickable .dz-message,.dropzone.dz-clickable .dz-message *{cursor:pointer}.dropzone.dz-started .dz-message{display:none}.dropzone.dz-drag-hover{border-style:solid}.dropzone.dz-drag-hover .dz-message{opacity:0.5}.dropzone .dz-message{text-align:center;margin:2em 0}.dropzone .dz-preview{position:relative;display:inline-block;vertical-align:top;margin:16px;min-height:100px}.dropzone .dz-preview:hover{z-index:1000}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview.dz-file-preview .dz-image{border-radius:20px;background:#999;background:linear-gradient(to bottom, #eee, #ddd)}.dropzone .dz-preview.dz-file-preview .dz-details{opacity:1}.dropzone .dz-preview.dz-image-preview{background:white}.dropzone .dz-preview.dz-image-preview .dz-details{-webkit-transition:opacity 0.2s linear;-moz-transition:opacity 0.2s linear;-ms-transition:opacity 0.2s linear;-o-transition:opacity 0.2s linear;transition:opacity 0.2s linear}.dropzone .dz-preview .dz-remove{font-size:14px;text-align:center;display:block;cursor:pointer;border:none}.dropzone .dz-preview .dz-remove:hover{text-decoration:underline}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview .dz-details{z-index:20;position:absolute;top:0;left:0;opacity:0;font-size:13px;min-width:100%;max-width:100%;padding:2em 1em;text-align:center;color:rgba(0,0,0,0.9);line-height:150%}.dropzone .dz-preview .dz-details .dz-size{margin-bottom:1em;font-size:16px}.dropzone .dz-preview .dz-details .dz-filename{white-space:nowrap}.dropzone .dz-preview .dz-details .dz-filename:hover span{border:1px solid rgba(200,200,200,0.8);background-color:rgba(255,255,255,0.8)}.dropzone .dz-preview .dz-details .dz-filename:not(:hover){overflow:hidden;text-overflow:ellipsis}.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span{border:1px solid transparent}.dropzone .dz-preview .dz-details .dz-filename span,.dropzone .dz-preview .dz-details .dz-size span{background-color:rgba(255,255,255,0.4);padding:0 0.4em;border-radius:3px}.dropzone .dz-preview:hover .dz-image img{-webkit-transform:scale(1.05, 1.05);-moz-transform:scale(1.05, 1.05);-ms-transform:scale(1.05, 1.05);-o-transform:scale(1.05, 1.05);transform:scale(1.05, 1.05);-webkit-filter:blur(8px);filter:blur(8px)}.dropzone .dz-preview .dz-image{border-radius:20px;overflow:hidden;width:120px;height:120px;position:relative;display:block;z-index:10}.dropzone .dz-preview .dz-image img{display:block}.dropzone .dz-preview.dz-success .dz-success-mark{-webkit-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-moz-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-ms-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-o-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview.dz-error .dz-error-mark{opacity:1;-webkit-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-moz-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-ms-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-o-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview .dz-success-mark,.dropzone .dz-preview .dz-error-mark{pointer-events:none;opacity:0;z-index:500;position:absolute;display:block;top:50%;left:50%;margin-left:-27px;margin-top:-27px}.dropzone .dz-preview .dz-success-mark svg,.dropzone .dz-preview .dz-error-mark svg{display:block;width:54px;height:54px}.dropzone .dz-preview.dz-processing .dz-progress{opacity:1;-webkit-transition:all 0.2s linear;-moz-transition:all 0.2s linear;-ms-transition:all 0.2s linear;-o-transition:all 0.2s linear;transition:all 0.2s linear}.dropzone .dz-preview.dz-complete .dz-progress{opacity:0;-webkit-transition:opacity 0.4s ease-in;-moz-transition:opacity 0.4s ease-in;-ms-transition:opacity 0.4s ease-in;-o-transition:opacity 0.4s ease-in;transition:opacity 0.4s ease-in}.dropzone .dz-preview:not(.dz-processing) .dz-progress{-webkit-animation:pulse 6s ease infinite;-moz-animation:pulse 6s ease infinite;-ms-animation:pulse 6s ease infinite;-o-animation:pulse 6s ease infinite;animation:pulse 6s ease infinite}.dropzone .dz-preview .dz-progress{opacity:1;z-index:1000;pointer-events:none;position:absolute;height:16px;left:50%;top:50%;margin-top:-8px;width:80px;margin-left:-40px;background:rgba(255,255,255,0.9);-webkit-transform:scale(1);border-radius:8px;overflow:hidden}.dropzone .dz-preview .dz-progress .dz-upload{background:#333;background:linear-gradient(to bottom, #666, #444);position:absolute;top:0;left:0;bottom:0;width:0;-webkit-transition:width 300ms ease-in-out;-moz-transition:width 300ms ease-in-out;-ms-transition:width 300ms ease-in-out;-o-transition:width 300ms ease-in-out;transition:width 300ms ease-in-out}.dropzone .dz-preview.dz-error .dz-error-message{display:block}.dropzone .dz-preview.dz-error:hover .dz-error-message{opacity:1;pointer-events:auto}.dropzone .dz-preview .dz-error-message{pointer-events:none;z-index:1000;position:absolute;display:block;display:none;opacity:0;-webkit-transition:opacity 0.3s ease;-moz-transition:opacity 0.3s ease;-ms-transition:opacity 0.3s ease;-o-transition:opacity 0.3s ease;transition:opacity 0.3s ease;border-radius:8px;font-size:13px;top:130px;left:-10px;width:140px;background:#be2626;background:linear-gradient(to bottom, #be2626, #a92222);padding:0.5em 1.2em;color:white}.dropzone .dz-preview .dz-error-message:after{content:'';position:absolute;top:-6px;left:64px;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #be2626} diff --git a/airtime_mvc/public/css/media_library.css b/airtime_mvc/public/css/media_library.css index ef078fd55..446cc62b3 100644 --- a/airtime_mvc/public/css/media_library.css +++ b/airtime_mvc/public/css/media_library.css @@ -37,7 +37,6 @@ #library_content { float: left; - width: 50%; overflow: auto; } diff --git a/airtime_mvc/public/css/showbuilder.css b/airtime_mvc/public/css/showbuilder.css index e9d1380b7..869148bf9 100644 --- a/airtime_mvc/public/css/showbuilder.css +++ b/airtime_mvc/public/css/showbuilder.css @@ -180,8 +180,8 @@ table.datatable tr.cursor-selected-row td, table.datatable tr.cursor-selected-ro background-color: rgba(255, 0, 0, 0.5); } -.sb-now-playing td { - background-color: rgba(23, 235, 37, 1) !important; +.sb-now-playing { + background-color: rgba(23, 235, 37, 1); } .sb-content.padded { diff --git a/airtime_mvc/public/css/styles.css b/airtime_mvc/public/css/styles.css index fad4eff17..d6ec22ad3 100644 --- a/airtime_mvc/public/css/styles.css +++ b/airtime_mvc/public/css/styles.css @@ -830,9 +830,9 @@ dl.inline-list dd { .datatable tr.odd.selected td { background-color: #c5deeb; } -.datatable tr.odd:hover td, .datatable tr.even:hover td { - background-color: #95d5f7 !important; -} +/*.datatable tr.odd:hover td, .datatable tr.even:hover td {*/ + /*background-color: #95d5f7 !important;*/ +/*}*/ .datatable tr td:first-child, .datatable tr th:first-child, .datatable tr th.ui-state-default:first-child { border-left-width:0 !important; @@ -3291,3 +3291,82 @@ dd .stream-status { #schedule_iframe { margin: 0 auto; } + +/* Show Builder*/ + +@media screen and (max-width: 1015px) { + .lib-test, .sb-test { + width: 100% !important; + } +} + +.lib-test legend, .lib-test label, .lib-test span { + color: #efefef; +} + +.lib-test { + margin: 2em 2em 2em 0; + overflow: hidden !important; +} + +.sb-test { + margin-top: 2em; +} + +.lib-test, .sb-test { + /* 1em for the middle margin, 6 for half the width of the left pane */ + width: calc(50% - 8em); + min-width: 470px; +} + +#media_type_nav { + float: left; + margin: 2em 0 0 0; + + width: 12em; + + background: none; + padding: 0 2em 0 0; +} + +#new_media_selector { + width: 100%; +} + +.media_type_selector { + cursor: pointer; + color: #cecece; + font-family: Roboto, "Open Sans", sans-serif; + font-size: 16px; + font-weight: 400; + width: 100%; + margin: 1em 1em 0 0; +} + +.media_type_selector.selected { + color: #fff; +} + +.media_type_selector:hover { + color: #fff; + -webkit-transition: color 0.2s linear; + -moz-transition: color 0.2s linear; + -o-transition: color 0.2s linear; + transition: color 0.2s linear; +} + +/* Uploads */ + +#upload_form { + width: 100%; + min-width: 470px; + + background: none; + border: 2px dashed #efefef; + + color: #efefef; + font-family: Roboto, "Open Sans", sans-serif; + font-size: 20px; + font-weight: 300; + line-height: 1.4rem; +} \ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js b/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js index d44cd1707..8dcfd651b 100644 --- a/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js +++ b/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js @@ -125,7 +125,9 @@ var AIRTIME = (function(AIRTIME) { } if (aSchedIds.length == 0) { - addToCurrentOrNext(aSchedIds); + if (!addToCurrentOrNext(aSchedIds)) { + return; + } } AIRTIME.showbuilder.fnAdd(aMediaIds, aSchedIds); @@ -139,6 +141,12 @@ var AIRTIME = (function(AIRTIME) { // the Now Playing screen if multiple shows are in view). el = $("[si_id="+$("#0").attr("si_id")+"]"); var temp = el.eq(-2).data("aData"); + + if (temp === undefined) { + alert($.i18n._("Cannot schedule outside a show.")); + return false; + } + arr.push({ "id" : temp.id, "instance" : temp.instance, diff --git a/airtime_mvc/public/js/airtime/library/library-test.js b/airtime_mvc/public/js/airtime/library/library-test.js new file mode 100644 index 000000000..ebfc80279 --- /dev/null +++ b/airtime_mvc/public/js/airtime/library/library-test.js @@ -0,0 +1,978 @@ +var AIRTIME = (function(AIRTIME) { + var mod, + libraryInit, + oTable, + $libContent, + $libTable, + LIB_SELECTED_CLASS = "lib-selected", + chosenItems = {}, + visibleChosenItems = {}, + $previouslySelected; + + + // we need to know whether the criteria value is string or + // numeric in order to provide a single textbox or range textboxes + // in the advanced search + // s => string + // n => numberic + var libraryColumnTypes = { + 0 : "", + "album_title" : "s", + "artist_name" : "s", + "bit_rate" : "n", + "bpm" : "n", + "comments" : "s", + "composer" : "s", + "conductor" : "s", + "copyright" : "s", + "cuein" : "n", + "cueout" : "n", + "utime" : "n", + "mtime" : "n", + "lptime" : "n", + "disc_number" : "n", + "encoded_by" : "s", + "genre" : "s", + "isrc_number" : "s", + "label" : "s", + "language" : "s", + "length" : "n", + "lyricist" : "s", + "mime" : "s", + "mood" : "s", + "name" : "s", + "orchestra" : "s", + "rating" : "n", + "sample_rate" : "n", + "track_title" : "s", + "track_num" : "n", + "year" : "n", + "owner_id" : "s", + "info_url" : "s", + "replay_gain" : "n" + }; + + if (AIRTIME.library === undefined) { + AIRTIME.library = {}; + } + mod = AIRTIME.library; + + mod.getChosenItemsLength = function(){ + var cItem, + selected, + $trs; + + // Get visible items and check if any chosenItems are visible + $trs = $libTable.find("tr"); + $trs.each(function(i){ + for (cItem in chosenItems) { + if (cItem === $(this).attr("id")) { + visibleChosenItems[cItem] = $(this).data('aData'); + } + } + }); + + selected = Object.keys(visibleChosenItems).length; + visibleChosenItems = {}; + return selected; + }; + + mod.getChosenAudioFilesLength = function(){ + // var files = Object.keys(chosenItems), + var files, + $trs, + cItem, + i, length, + count = 0, + reAudio=/^(au|st|pl|bl)/ ; + + // Get visible items and check if any chosenItems are visible + $trs = $libTable.find("tr"); + $trs.each(function(i){ + for (cItem in chosenItems) { + if (cItem === $(this).attr("id")) { + visibleChosenItems[cItem] = $(this).data('aData'); + } + } + }); + + files = Object.keys(visibleChosenItems); + + for (i = 0, length = files.length; i < length; i++) { + + if (files[i].search(reAudio) !== -1) { + count++; + } + } + visibleChosenItems = {}; + return count; + }; + + mod.changeAddButtonText = function($button, btnText) { + $button.text(btnText); + }; + + mod.createToolbarButtons = function() { + $menu = $("
"); + $menu + .append("
" + + "" + + "" + + "
") + .append("
" + + "" + + "
") + .append("
" + + "" + + "
"); + }; + + mod.createToolbarDropDown = function() { + $('#sb-select-page').click(function(){mod.selectCurrentPage();}); + $('#sb-dselect-page').click(function(){mod.deselectCurrentPage();}); + $('#sb-dselect-all').click(function(){mod.selectNone();}); + }; + + mod.checkDeleteButton = function() { + var selected = mod.getChosenItemsLength(), + check = false; + + if (selected !== 0) { + check = true; + } + + if (check === true) { + AIRTIME.button.enableButton("btn-group #sb-trash", false); + } + else { + AIRTIME.button.disableButton("btn-group #sb-trash", false); + } + }; + + mod.checkToolBarIcons = function() { + + AIRTIME.library.checkAddButton(); + AIRTIME.library.checkDeleteButton(); + }; + + mod.getSelectedData = function() { + var id, + data = [], + cItem, + $trs; + + $.fn.reverse = [].reverse; + + // Get visible items and check if any chosenItems are visible + $trs = $libTable.find("tr").reverse(); + $trs.each(function(i){ + for (cItem in chosenItems) { + if (cItem === $(this).attr("id")) { + visibleChosenItems[cItem] = $(this).data('aData'); + } + } + }); + + for (id in visibleChosenItems) { + if (visibleChosenItems.hasOwnProperty(id)) { + data.push(visibleChosenItems[id]); + } + } + visibleChosenItems = {}; + return data; + }; + + mod.redrawChosen = function() { + var ids = Object.keys(chosenItems), + i, length, + $el; + + for (i = 0, length = ids.length; i < length; i++) { + $el = $libTable.find("#"+ids[i]); + + if ($el.length !== 0) { + mod.highlightItem($el); + } + } + }; + + mod.isChosenItem = function($el) { + var id = $el.attr("id"), + item = chosenItems[id]; + + return item !== undefined; + }; + + mod.addToChosen = function($el) { + var id = $el.attr("id"); + + chosenItems[id] = $el.data('aData'); + }; + + mod.removeFromChosen = function($el) { + var id = $el.attr("id"); + + // used to not keep dragged items selected. + if (!$el.hasClass(LIB_SELECTED_CLASS)) { + delete chosenItems[id]; + } + }; + + mod.highlightItem = function($el) { + $el.addClass(LIB_SELECTED_CLASS); + }; + + mod.unHighlightItem = function($el) { + $el.removeClass(LIB_SELECTED_CLASS); + }; + + mod.selectItem = function($el) { + mod.highlightItem($el); + mod.addToChosen($el); + + mod.checkToolBarIcons(); + }; + + mod.deselectItem = function($el) { + mod.unHighlightItem($el); + mod.removeFromChosen($el); + mod.checkToolBarIcons(); + }; + + /* + * selects all items which the user can currently see. (behaviour taken from + * gmail) + * + * by default the items are selected in reverse order so we need to reverse + * it back + */ + mod.selectCurrentPage = function() { + $.fn.reverse = [].reverse; + var $trs = $libTable.find("tbody").find("tr").reverse(); + $trs.addClass(LIB_SELECTED_CLASS); + + $trs.each(function(i, el){ + $el = $(this); + mod.addToChosen($el); + }); + + mod.checkToolBarIcons(); + + }; + + /* + * deselects all items that the user can currently see. (behaviour taken + * from gmail) + */ + mod.deselectCurrentPage = function() { + var $trs = $libTable.find("tr"), id; + $trs.removeClass(LIB_SELECTED_CLASS); + + $trs.each(function(i, el){ + $el = $(this); + id = $el.attr("id"); + delete chosenItems[id]; + }); + + mod.checkToolBarIcons(); + }; + + mod.selectNone = function() { + var $trs = $libTable.find("tr"); + $trs.removeClass(LIB_SELECTED_CLASS); + + chosenItems = {}; + + mod.checkToolBarIcons(); + }; + + mod.fnDeleteItems = function(aMedia) { + + //Prevent the user from spamming the delete button while the AJAX request is in progress + AIRTIME.button.disableButton("btn-group #sb-trash", false); + //Hack to immediately show the "Processing" div in DataTables to give the user some sort of feedback. + $(".dataTables_processing").css('visibility','visible'); + + $.post(baseUrl+"library/delete", + {"format": "json", "media": aMedia}, + function(json){ + if (json.message !== undefined) { + alert(json.message); + } + + chosenItems = {}; + oTable.fnStandingRedraw(); + + //Re-enable the delete button + AIRTIME.button.enableButton("btn-group #sb-trash", false); + }); + }; + + mod.fnDeleteSelectedItems = function() { + if (confirm($.i18n._('Are you sure you want to delete the selected item(s)?'))) { + var aData = AIRTIME.library.getSelectedData(), + item, + temp, + aMedia = [], + currentObjId = $("#side_playlist").find("#obj_id").val(), + currentObjType = $("#side_playlist").find("#obj_type").val(), + closeObj = false; + + // process selected files/playlists. + for (item in aData) { + temp = aData[item]; + if (temp !== null && temp.hasOwnProperty('id') ) { + aMedia.push({"id": temp.id, "type": temp.ftype}); + if ( (temp.id == currentObjId && temp.ftype === currentObjType) || + temp.id == currentObjId && temp.ftype === "stream" && currentObjType === "webstream") { + closeObj = true; + } + } + } + + AIRTIME.library.fnDeleteItems(aMedia); + + // close the object (playlist/block/webstream) + // on the right side if it was just deleted + // from the library + if (closeObj) { + $.post(baseUrl+"playlist/close-playlist", + {"format": "json", "type": currentObjType}, + function(json) { + $("#side_playlist").empty().append(json.html); + }); + } + } + }; + + libraryInit = function() { + + $libContent = $("#library_content"); + + /* + * Icon hover states in the toolbar. + */ + $libContent.on("mouseenter", ".fg-toolbar ul li", function(ev) { + $el = $(this); + + if (!$el.hasClass("ui-state-disabled")) { + $el.addClass("ui-state-hover"); + } + }); + $libContent.on("mouseleave", ".fg-toolbar ul li", function(ev) { + $el = $(this); + + if (!$el.hasClass("ui-state-disabled")) { + $el.removeClass("ui-state-hover"); + } + }); + + var colReorderMap = new Array(); + + $libTable = $libContent.find("table"); + + function getTableHeight() { + return $libContent.height() - 175; + } + + function setColumnFilter(oTable){ + // TODO : remove this dirty hack once js is refactored + if (!oTable.fnSettings()) { return ; } + var aoCols = oTable.fnSettings().aoColumns; + var colsForAdvancedSearch = new Array(); + var advanceSearchDiv = $("div#advanced_search"); + advanceSearchDiv.empty(); + $.each(aoCols, function(i,ele){ + if (ele.bSearchable) { + var currentColId = ele._ColReorder_iOrigCol; + + var inputClass = 'filter_column filter_number_text'; + var labelStyle = "style='margin-right:35px;'"; + if (libraryColumnTypes[ele.mDataProp] != "s") { + inputClass = 'filterColumn filter_number_range'; + labelStyle = ""; + } + + if (ele.bVisible) { + advanceSearchDiv.append( + "
" + + "" + + "
" + + "
"); + } else { + advanceSearchDiv.append( + ""); + } + + if (libraryColumnTypes[ele.mDataProp] == "s") { + var obj = { sSelector: "#"+ele.mDataProp } + } else { + var obj = { sSelector: "#"+ele.mDataProp, type: "number-range" } + } + colsForAdvancedSearch.push(obj); + } else { + colsForAdvancedSearch.push(null); + } + }); + + oTable.columnFilter({ + aoColumns: colsForAdvancedSearch, + bUseColVis: true, + sPlaceHolder: "head:before" + } + ); + } + + function setFilterElement(iColumn, bVisible){ + var actualId = colReorderMap[iColumn]; + var selector = "div#advanced_search_col_"+actualId; + var $el = $(selector); + + if (bVisible) { + $el.show(); + } else { + $el.hide(); + } + + //resize to prevent double scroll bars. + var $fs = $el.parents("fieldset"), + tableHeight = getTableHeight(), + searchHeight = $fs.height(); + + $libContent.find(".dataTables_scrolling").css("max-height", tableHeight - searchHeight); + } + + oTable = $libTable.dataTable( { + + // put hidden columns at the top to insure they can never be visible + // on the table through column reordering. + + //IMPORTANT: WHEN ADDING A NEW COLUMN PLEASE CONSULT WITH THE WIKI + // https://wiki.sourcefabric.org/display/CC/Adding+a+new+library+datatable+column + "aoColumns": [ + /* ftype */ { "sTitle" : "" , "mDataProp" : "ftype" , "bSearchable" : false , "bVisible" : false } , + /* Type */ { "sTitle" : "" , "mDataProp" : "image" , "bSearchable" : false , "sWidth" : "16px" , "sClass" : "library_type" , "iDataSort" : 0 } , + ///* Is Scheduled */ { "sTitle" : $.i18n._("Scheduled") , "mDataProp" : "is_scheduled" , "bVisible" : false , "bSearchable" : false , "sWidth" : "90px" , "sClass" : "library_is_scheduled"} , + /* Is Playlist */ { "sTitle" : $.i18n._("Playlist / Block") , "mDataProp" : "is_playlist" , "bSearchable" : false , "sWidth" : "110px" , "sClass" : "library_is_playlist"} , + /* Title */ { "sTitle" : $.i18n._("Title") , "mDataProp" : "track_title" , "sClass" : "library_title" , "sWidth" : "170px" } , + /* Creator */ { "sTitle" : $.i18n._("Creator") , "mDataProp" : "artist_name" , "sClass" : "library_creator" , "sWidth" : "160px" } , + /* Album */ { "sTitle" : $.i18n._("Album") , "mDataProp" : "album_title" , "sClass" : "library_album" , "sWidth" : "150px" } , + /* Bit Rate */ { "sTitle" : $.i18n._("Bit Rate") , "mDataProp" : "bit_rate" , "bVisible" : false , "sClass" : "library_bitrate" , "sWidth" : "80px" }, + /* BPM */ { "sTitle" : $.i18n._("BPM") , "mDataProp" : "bpm" , "bVisible" : false , "sClass" : "library_bpm" , "sWidth" : "50px" }, + /* Composer */ { "sTitle" : $.i18n._("Composer") , "mDataProp" : "composer" , "bVisible" : false , "sClass" : "library_composer" , "sWidth" : "150px" }, + /* Conductor */ { "sTitle" : $.i18n._("Conductor") , "mDataProp" : "conductor" , "bVisible" : false , "sClass" : "library_conductor" , "sWidth" : "125px" }, + /* Copyright */ { "sTitle" : $.i18n._("Copyright") , "mDataProp" : "copyright" , "bVisible" : false , "sClass" : "library_copyright" , "sWidth" : "125px" }, + /* Cue In */ { "sTitle" : $.i18n._("Cue In") , "mDataProp" : "cuein" , "bVisible" : false , "sClass" : "library_length" , "sWidth" : "80px" }, + /* Cue Out */ { "sTitle" : $.i18n._("Cue Out") , "mDataProp" : "cueout" , "bVisible" : false , "sClass" : "library_length" , "sWidth" : "80px" }, + /* Encoded */ { "sTitle" : $.i18n._("Encoded By") , "mDataProp" : "encoded_by" , "bVisible" : false , "sClass" : "library_encoded" , "sWidth" : "150px" }, + /* Genre */ { "sTitle" : $.i18n._("Genre") , "mDataProp" : "genre" , "bVisible" : false , "sClass" : "library_genre" , "sWidth" : "100px" }, + /* ISRC Number */ { "sTitle" : $.i18n._("ISRC") , "mDataProp" : "isrc_number" , "bVisible" : false , "sClass" : "library_isrc" , "sWidth" : "150px" }, + /* Label */ { "sTitle" : $.i18n._("Label") , "mDataProp" : "label" , "bVisible" : false , "sClass" : "library_label" , "sWidth" : "125px" }, + /* Language */ { "sTitle" : $.i18n._("Language") , "mDataProp" : "language" , "bVisible" : false , "sClass" : "library_language" , "sWidth" : "125px" }, + /* Last Modified */ { "sTitle" : $.i18n._("Last Modified") , "mDataProp" : "mtime" , "bVisible" : false , "sClass" : "library_modified_time" , "sWidth" : "125px" }, + /* Last Played */ { "sTitle" : $.i18n._("Last Played") , "mDataProp" : "lptime" , "bVisible" : false , "sClass" : "library_modified_time" , "sWidth" : "125px" }, + /* Length */ { "sTitle" : $.i18n._("Length") , "mDataProp" : "length" , "sClass" : "library_length" , "sWidth" : "80px" } , + /* Mime */ { "sTitle" : $.i18n._("Mime") , "mDataProp" : "mime" , "bVisible" : false , "sClass" : "library_mime" , "sWidth" : "80px" }, + /* Mood */ { "sTitle" : $.i18n._("Mood") , "mDataProp" : "mood" , "bVisible" : false , "sClass" : "library_mood" , "sWidth" : "70px" }, + /* Owner */ { "sTitle" : $.i18n._("Owner") , "mDataProp" : "owner_id" , "bVisible" : false , "sClass" : "library_language" , "sWidth" : "125px" }, + /* Replay Gain */ { "sTitle" : $.i18n._("Replay Gain") , "mDataProp" : "replay_gain" , "bVisible" : false , "sClass" : "library_replay_gain" , "sWidth" : "80px" }, + /* Sample Rate */ { "sTitle" : $.i18n._("Sample Rate") , "mDataProp" : "sample_rate" , "bVisible" : false , "sClass" : "library_sr" , "sWidth" : "80px" }, + /* Track Number */ { "sTitle" : $.i18n._("Track Number") , "mDataProp" : "track_number" , "bVisible" : false , "sClass" : "library_track" , "sWidth" : "65px" }, + /* Upload Time */ { "sTitle" : $.i18n._("Uploaded") , "mDataProp" : "utime" , "bVisible" : false , "sClass" : "library_upload_time" , "sWidth" : "125px" } , + /* Website */ { "sTitle" : $.i18n._("Website") , "mDataProp" : "info_url" , "bVisible" : false , "sClass" : "library_url" , "sWidth" : "150px" }, + /* Year */ { "sTitle" : $.i18n._("Year") , "mDataProp" : "year" , "bVisible" : false , "sClass" : "library_year" , "sWidth" : "60px" } + ], + + "bProcessing": true, + "bServerSide": true, + + "aLengthMenu": [[5, 10, 15, 20, 25, 50, 100], [5, 10, 15, 20, 25, 50, 100]], + + "bStateSave": true, + "fnStateSaveParams": function (oSettings, oData) { + // remove oData components we don't want to save. + delete oData.oSearch; + delete oData.aoSearchCols; + }, + "fnStateSave": function (oSettings, oData) { + localStorage.setItem('datatables-library', JSON.stringify(oData)); + /* + $.ajax({ + url: baseUrl+"usersettings/set-library-datatable", + type: "POST", + data: {settings : oData, format: "json"}, + dataType: "json" + }); + */ + + colReorderMap = oData.ColReorder; + }, + "fnStateLoad": function fnLibStateLoad(oSettings) { + var settings = localStorage.getItem('datatables-library'); + + try { + return JSON.parse(settings); + } catch (e) { + return null; + } + }, + "fnStateLoadParams": function (oSettings, oData) { + var i, + length, + a = oData.abVisCols; + + if (a) { + // putting serialized data back into the correct js type to make + // sure everything works properly. + for (i = 0, length = a.length; i < length; i++) { + if (typeof(a[i]) === "string") { + a[i] = (a[i] === "true") ? true : false; + } + } + } + + a = oData.ColReorder; + if (a) { + for (i = 0, length = a.length; i < length; i++) { + if (typeof(a[i]) === "string") { + a[i] = parseInt(a[i], 10); + } + } + } + + oData.iEnd = parseInt(oData.iEnd, 10); + oData.iLength = parseInt(oData.iLength, 10); + oData.iStart = parseInt(oData.iStart, 10); + oData.iCreate = parseInt(oData.iCreate, 10); + }, + + "sAjaxSource": baseUrl+"Library/contents-feed-test", + "sAjaxDataProp": "files", + + "fnServerData": function ( sSource, aoData, fnCallback ) { + /* + * The real validation check is done in + * dataTables.columnFilter.js We also need to check it here + * because datatable is redrawn everytime an action is performed + * in the Library page. In order for datatable to redraw the + * advanced search fields MUST all be valid. + */ + var advSearchFields = $("div#advanced_search").children(':visible'); + var advSearchValid = validateAdvancedSearch(advSearchFields); + var type; + aoData.push( { name: "format", value: "json"} ); + aoData.push( { name: "advSearch", value: advSearchValid} ); + + // push whether to search files/playlists or all. + type = $(".media_type_selector.selected").attr("selection_id"); + type = (type === undefined) ? 1 : type; + aoData.push( { name: "type", value: type} ); + + $.ajax( { + "dataType": 'json', + "type": "POST", + "url": sSource, + "data": aoData, + "success": fnCallback + } ); + }, + "fnRowCallback": AIRTIME.library.fnRowCallback, + "fnCreatedRow": function( nRow, aData, iDataIndex ) { + // add audio preview image/button + if (aData.ftype === "audioclip") { + $(nRow).find('td.library_type').html(''); + } else if (aData.ftype === "playlist") { + $(nRow).find('td.library_type').html(''); + } else if (aData.ftype === "block") { + $(nRow).find('td.library_type').html(''); + } else if (aData.ftype === "stream") { + $(nRow).find('td.library_type').html(''); + } + + if (aData.is_scheduled) { + $(nRow).find("td.library_is_scheduled").html(''); + } else if (!aData.is_scheduled) { + $(nRow).find("td.library_is_scheduled").html(''); + } + if (aData.is_playlist) { + $(nRow).find("td.library_is_playlist").html(''); + } else if (!aData.is_playlist) { + $(nRow).find("td.library_is_playlist").html(''); + } + + // add the play function to the library_type td + $(nRow).find('td.library_type').click(function(){ + if (aData.ftype === 'playlist' && aData.length !== '0.0'){ + open_playlist_preview(aData.audioFile, 0); + } else if (aData.ftype === 'audioclip') { + if (isAudioSupported(aData.mime)) { + open_audio_preview(aData.ftype, aData.id); + } + } else if (aData.ftype == 'stream') { + if (isAudioSupported(aData.mime)) { + open_audio_preview(aData.ftype, aData.id); + } + } else if (aData.ftype == 'block' && aData.bl_type == 'static') { + open_block_preview(aData.audioFile, 0); + } + return false; + }); + }, + // remove any selected nodes before the draw. + "fnPreDrawCallback": function( oSettings ) { + + // make sure any dragging helpers are removed or else they'll be + // stranded on the screen. + $("#draggingContainer").remove(); + }, + "fnDrawCallback": AIRTIME.library.fnDrawCallback, + + "aaSorting": [[5, 'asc']], + "sPaginationType": "full_numbers", + "bJQueryUI": true, + "bAutoWidth": false, + "oLanguage": datatables_dict, + + // R = ColReorder, C = ColVis + "sDom": 'Rl<"#library_display_type">f<"dt-process-rel"r><"H"<"library_toolbar"C>><"dataTables_scrolling"t><"F"ip>', + + "oColVis": { + "sAlign": "right", + "aiExclude": [0, 1, 2], + "sSize": "css", + "fnStateChange": setFilterElement, + "buttonText": $.i18n._("Show / hide columns") + }, + + "oColReorder": { + "iFixedColumns": 3 + } + + }); + + setColumnFilter(oTable); + oTable.fnSetFilteringDelay(350); + + var simpleSearchText; + + $libContent.on("click", "legend", function(){ + $simpleSearch = $libContent.find("#library_display_filter label"); + var $fs = $(this).parents("fieldset"), + searchHeight, + tableHeight = getTableHeight(), + height; + + if ($fs.hasClass("closed")) { + $fs.removeClass("closed"); + searchHeight = $fs.height(); + + //keep value of simple search for when user switches back to it + simpleSearchText = $simpleSearch.find('input').val(); + + // clear the simple search text field and reset datatable + $(".dataTables_filter input").val("").keyup(); + + $simpleSearch.addClass("sp-invisible"); + + //resize the library table to avoid a double scroll bar. CC-4504 + height = tableHeight - searchHeight; + $libContent.find(".dataTables_scrolling").css("max-height", height); + } + else { + // clear the advanced search fields + var divs = $("div#advanced_search").children(':visible'); + $.each(divs, function(i, div){ + fields = $(div).children().find('input'); + $.each(fields, function(i, field){ + if ($(field).val() !== "") { + $(field).val(""); + // we need to reset the results when removing + // an advanced search field + $(field).keyup(); + } + }); + }); + + //reset datatable with previous simple search results (if any) + $(".dataTables_filter input").val(simpleSearchText).keyup(); + + $simpleSearch.removeClass("sp-invisible"); + $fs.addClass("closed"); + + //resize the library table to avoid a double scroll bar. CC-4504 + $libContent.find(".dataTables_scrolling").css("max-height", tableHeight); + } + }); + + var tableHeight = getTableHeight(); + $libContent.find(".dataTables_scrolling").css("max-height", tableHeight); + + AIRTIME.library.setupLibraryToolbar(oTable); + + $libTable.find("tbody").on("dblclick", "tr", function(ev) { + var $tr = $(this), + data = $tr.data("aData"); + AIRTIME.library.dblClickAdd(data, data.ftype); + }); + + $libTable.find("tbody").on("click", "tr", function(ev) { + var $tr = $(this), + // Get the ID of the selected row + $rowId = $tr.attr("id"); + + if (ev.shiftKey && $previouslySelected !== undefined) { + if ($previouslySelected.attr("id") == $rowId) { + return; + } + + // If the selected row comes before the previously selected row, + // we want to select previous rows, otherwise we select next + if ($previouslySelected.prevAll("#"+$rowId).length !== 0) { + $previouslySelected.prevUntil($tr).each(function(i, el){ + mod.selectItem($(el)); + }); + } else { + $previouslySelected.nextUntil($tr).each(function(i, el){ + mod.selectItem($(el)); + }); + } + + mod.selectItem($tr); + } else if (ev.ctrlKey && $previouslySelected !== undefined) { + mod.selectItem($tr); + } else { + $("."+LIB_SELECTED_CLASS).each(function(i, el) { + mod.deselectItem($(el)) + }); + mod.selectItem($tr); + } + + // Remember this row so we can properly multiselect + $previouslySelected = $tr; + }); + }; + mod.libraryInit = libraryInit; + + return AIRTIME; + +}(AIRTIME || {})); + +function buildEditMetadataDialog (json){ + var dialog = $(json.dialog); + + dialog.dialog({ + autoOpen: false, + title: $.i18n._("Edit Metadata"), + width: 460, + height: 660, + modal: true, + close: closeDialogLibrary + }); + + dialog.dialog('open'); +} + +function closeDialogLibrary(event, ui) { + $(this).remove(); +} + +/* + * This function is called from dataTables.columnFilter.js + */ +function validateAdvancedSearch(divs) { + var valid, + allValid = true, + fieldName, + fields, + searchTerm = Array(), + searchTermType, + regExpr, + timeRegEx = "\\d{2}[:]([0-5]){1}([0-9]){1}[:]([0-5]){1}([0-9]){1}([.]\\d{1,6})?", + dateRegEx = "\\d{4}[-]\\d{2}[-]\\d{2}?", + integerRegEx = "^\\d+$", + numericRegEx = "^\\d+[.]?\\d*$"; + + searchTerm[0] = ""; + searchTerm[1] = ""; + $.each(divs, function(i, div){ + fieldName = $(div).children(':nth-child(2)').attr('id'); + fields = $(div).children().find('input'); + searchTermType = validationTypes[fieldName]; + valid = true; + + $.each(fields, function(i, field){ + searchTerm[i] = $(field).val(); + + if (searchTerm[i] !== "") { + + if (searchTermType === "l") { + regExpr = new RegExp("^" +timeRegEx+ "$"); + } else if (searchTermType === "t") { + var pieces = searchTerm[i].split(" "); + if (pieces.length === 2) { + regExpr = new RegExp("^" +dateRegEx+ " " +timeRegEx+ "$"); + } else if (pieces.length === 1) { + regExpr = new RegExp("^" +dateRegEx+ "$"); + } + } else if (searchTermType === "i") { + regExpr = new RegExp(integerRegEx); + } else if (searchTermType === "n") { + regExpr = new RegExp(numericRegEx); + if (searchTerm[i].charAt(0) === "-") { + searchTerm[i] = searchTerm[i].substr(1); + } + } + + // string fields do not need validation + if (searchTermType !== "s") { + valid = regExpr.test(searchTerm[i]); + if (!valid) allValid = false; + } + + addRemoveValidationIcons(valid, $(field), searchTermType); + + /* + * Empty fields should not have valid/invalid indicator Range values + * are considered valid even if only the 'From' value is provided. + * Therefore, if the 'To' value is empty but the 'From' value is not + * empty we need to keep the validation icon on screen. + */ + } else if (searchTerm[0] === "" && searchTerm[1] !== "" || + searchTerm[0] === "" && searchTerm[1] === ""){ + if ($(field).closest('div').children(':last-child').hasClass('checked-icon') || + $(field).closest('div').children(':last-child').hasClass('not-available-icon')) { + $(field).closest('div').children(':last-child').remove(); + } + } + + if (!valid) { + return false; + } + }); + }); + + return allValid; +} + +function addRemoveValidationIcons(valid, field, searchTermType) { + var title = ''; + if (searchTermType === 'i') { + title = $.i18n._('Input must be a positive number'); + } else if (searchTermType === 'n') { + title = $.i18n._('Input must be a number'); + } else if (searchTermType === 't') { + title = $.i18n._('Input must be in the format: yyyy-mm-dd'); + } else if (searchTermType === 'l') { + title = $.i18n._('Input must be in the format: hh:mm:ss.t'); + } + + var validIndicator = " ", + invalidIndicator = " "; + + if (valid) { + if (!field.closest('div').children(':last-child').hasClass('checked-icon')) { + // remove invalid icon before adding valid icon + if (field.closest('div').children(':last-child').hasClass('not-available-icon')) { + field.closest('div').children(':last-child').remove(); + } + field.closest('div').append(validIndicator); + } + } else { + if (!field.closest('div').children(':last-child').hasClass('not-available-icon')) { + // remove valid icon before adding invalid icon + if (field.closest('div').children(':last-child').hasClass('checked-icon')) { + field.closest('div').children(':last-child').remove(); + } + field.closest('div').append(invalidIndicator); + } + } +} + +/* + * Validation types: s => string i => integer n => numeric (positive/negative, + * whole/decimals) t => timestamp l => length + */ +var validationTypes = { + "album_title" : "s", + "artist_name" : "s", + "bit_rate" : "i", + "bpm" : "i", + "comments" : "s", + "composer" : "s", + "conductor" : "s", + "copyright" : "s", + "cuein" : "l", + "cueout" : "l", + "encoded_by" : "s", + "utime" : "t", + "mtime" : "t", + "lptime" : "t", + "disc_number" : "i", + "genre" : "s", + "isrc_number" : "s", + "label" : "s", + "language" : "s", + "length" : "l", + "lyricist" : "s", + "mood" : "s", + "mime" : "s", + "name" : "s", + "orchestra" : "s", + "owner_id" : "s", + "rating" : "i", + "replay_gain" : "n", + "sample_rate" : "n", + "track_title" : "s", + "track_number" : "i", + "info_url" : "s", + "year" : "i" +}; + +$(document).ready(function() { + $('#editmdsave').live("click", function() { + var file_id = $('#file_id').val(), + data = $("#edit-md-dialog form").serializeArray(); + $.post(baseUrl+'library/edit-file-md', {format: "json", id: file_id, data: data}, function() { + $("#edit-md-dialog").dialog().remove(); + + // don't redraw the library table if we are on calendar page + // we would be on calendar if viewing recorded file metadata + if ($("#schedule_calendar").length === 0) { + oTable.fnStandingRedraw(); + } + }); + }); + + $('#editmdcancel').live("click", function() { + $("#edit-md-dialog").dialog().remove(); + }); + + $('#edit-md-dialog').live("keyup", function(event) { + if (event.keyCode === 13) { + $('#editmdsave').click(); + } + }); + + $(".media_type_selector").on("click", function() { + $(".media_type_selector").each(function() { + $(this).removeClass("selected"); + }); + $(this).addClass("selected"); + oTable.fnDraw(); + }); +}); + diff --git a/airtime_mvc/public/js/airtime/library/library.js b/airtime_mvc/public/js/airtime/library/library.js index 0e4d97723..b752b3e87 100644 --- a/airtime_mvc/public/js/airtime/library/library.js +++ b/airtime_mvc/public/js/airtime/library/library.js @@ -484,35 +484,35 @@ var AIRTIME = (function(AIRTIME) { //IMPORTANT: WHEN ADDING A NEW COLUMN PLEASE CONSULT WITH THE WIKI // https://wiki.sourcefabric.org/display/CC/Adding+a+new+library+datatable+column "aoColumns": [ - /* ftype */ { "sTitle" : "" , "mDataProp" : "ftype" , "bSearchable" : false , "bVisible" : false } , - /* Checkbox */ { "sTitle" : "" , "mDataProp" : "checkbox" , "bSortable" : false , "bSearchable" : false , "sWidth" : "25px" , "sClass" : "library_checkbox" } , + /* 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 } , /* Is Scheduled */ { "sTitle" : $.i18n._("Scheduled") , "mDataProp" : "is_scheduled" , "bSearchable" : false , "sWidth" : "90px" , "sClass" : "library_is_scheduled"} , /* Is Playlist */ { "sTitle" : $.i18n._("Playlist / Block") , "mDataProp" : "is_playlist" , "bSearchable" : false , "sWidth" : "110px" , "sClass" : "library_is_playlist"} , - /* Title */ { "sTitle" : $.i18n._("Title") , "mDataProp" : "track_title" , "sClass" : "library_title" , "sWidth" : "170px" } , - /* Creator */ { "sTitle" : $.i18n._("Creator") , "mDataProp" : "artist_name" , "sClass" : "library_creator" , "sWidth" : "160px" } , - /* Album */ { "sTitle" : $.i18n._("Album") , "mDataProp" : "album_title" , "sClass" : "library_album" , "sWidth" : "150px" } , - /* Bit Rate */ { "sTitle" : $.i18n._("Bit Rate") , "mDataProp" : "bit_rate" , "bVisible" : false , "sClass" : "library_bitrate" , "sWidth" : "80px" }, + /* Title */ { "sTitle" : $.i18n._("Title") , "mDataProp" : "track_title" , "sClass" : "library_title" , "sWidth" : "170px" } , + /* Creator */ { "sTitle" : $.i18n._("Creator") , "mDataProp" : "artist_name" , "sClass" : "library_creator" , "sWidth" : "160px" } , + /* Album */ { "sTitle" : $.i18n._("Album") , "mDataProp" : "album_title" , "sClass" : "library_album" , "sWidth" : "150px" } , + /* Bit Rate */ { "sTitle" : $.i18n._("Bit Rate") , "mDataProp" : "bit_rate" , "bVisible" : false , "sClass" : "library_bitrate" , "sWidth" : "80px" }, /* BPM */ { "sTitle" : $.i18n._("BPM") , "mDataProp" : "bpm" , "bVisible" : false , "sClass" : "library_bpm" , "sWidth" : "50px" }, - /* Composer */ { "sTitle" : $.i18n._("Composer") , "mDataProp" : "composer" , "bVisible" : false , "sClass" : "library_composer" , "sWidth" : "150px" }, + /* Composer */ { "sTitle" : $.i18n._("Composer") , "mDataProp" : "composer" , "bVisible" : false , "sClass" : "library_composer" , "sWidth" : "150px" }, /* Conductor */ { "sTitle" : $.i18n._("Conductor") , "mDataProp" : "conductor" , "bVisible" : false , "sClass" : "library_conductor" , "sWidth" : "125px" }, /* Copyright */ { "sTitle" : $.i18n._("Copyright") , "mDataProp" : "copyright" , "bVisible" : false , "sClass" : "library_copyright" , "sWidth" : "125px" }, /* Cue In */ { "sTitle" : $.i18n._("Cue In") , "mDataProp" : "cuein" , "bVisible" : false , "sClass" : "library_length" , "sWidth" : "80px" }, /* Cue Out */ { "sTitle" : $.i18n._("Cue Out") , "mDataProp" : "cueout" , "bVisible" : false , "sClass" : "library_length" , "sWidth" : "80px" }, - /* Encoded */ { "sTitle" : $.i18n._("Encoded By") , "mDataProp" : "encoded_by" , "bVisible" : false , "sClass" : "library_encoded" , "sWidth" : "150px" }, - /* Genre */ { "sTitle" : $.i18n._("Genre") , "mDataProp" : "genre" , "bVisible" : false , "sClass" : "library_genre" , "sWidth" : "100px" }, - /* ISRC Number */ { "sTitle" : $.i18n._("ISRC") , "mDataProp" : "isrc_number" , "bVisible" : false , "sClass" : "library_isrc" , "sWidth" : "150px" }, - /* Label */ { "sTitle" : $.i18n._("Label") , "mDataProp" : "label" , "bVisible" : false , "sClass" : "library_label" , "sWidth" : "125px" }, - /* Language */ { "sTitle" : $.i18n._("Language") , "mDataProp" : "language" , "bVisible" : false , "sClass" : "library_language" , "sWidth" : "125px" }, + /* Encoded */ { "sTitle" : $.i18n._("Encoded By") , "mDataProp" : "encoded_by" , "bVisible" : false , "sClass" : "library_encoded" , "sWidth" : "150px" }, + /* Genre */ { "sTitle" : $.i18n._("Genre") , "mDataProp" : "genre" , "bVisible" : false , "sClass" : "library_genre" , "sWidth" : "100px" }, + /* ISRC Number */ { "sTitle" : $.i18n._("ISRC") , "mDataProp" : "isrc_number" , "bVisible" : false , "sClass" : "library_isrc" , "sWidth" : "150px" }, + /* Label */ { "sTitle" : $.i18n._("Label") , "mDataProp" : "label" , "bVisible" : false , "sClass" : "library_label" , "sWidth" : "125px" }, + /* Language */ { "sTitle" : $.i18n._("Language") , "mDataProp" : "language" , "bVisible" : false , "sClass" : "library_language" , "sWidth" : "125px" }, /* Last Modified */ { "sTitle" : $.i18n._("Last Modified") , "mDataProp" : "mtime" , "bVisible" : false , "sClass" : "library_modified_time" , "sWidth" : "125px" }, - /* Last Played */ { "sTitle" : $.i18n._("Last Played") , "mDataProp" : "lptime" , "bVisible" : false , "sClass" : "library_modified_time" , "sWidth" : "125px" }, - /* Length */ { "sTitle" : $.i18n._("Length") , "mDataProp" : "length" , "sClass" : "library_length" , "sWidth" : "80px" } , - /* Mime */ { "sTitle" : $.i18n._("Mime") , "mDataProp" : "mime" , "bVisible" : false , "sClass" : "library_mime" , "sWidth" : "80px" }, + /* Last Played */ { "sTitle" : $.i18n._("Last Played") , "mDataProp" : "lptime" , "bVisible" : false , "sClass" : "library_modified_time" , "sWidth" : "125px" }, + /* Length */ { "sTitle" : $.i18n._("Length") , "mDataProp" : "length" , "sClass" : "library_length" , "sWidth" : "80px" } , + /* Mime */ { "sTitle" : $.i18n._("Mime") , "mDataProp" : "mime" , "bVisible" : false , "sClass" : "library_mime" , "sWidth" : "80px" }, /* Mood */ { "sTitle" : $.i18n._("Mood") , "mDataProp" : "mood" , "bVisible" : false , "sClass" : "library_mood" , "sWidth" : "70px" }, - /* Owner */ { "sTitle" : $.i18n._("Owner") , "mDataProp" : "owner_id" , "bVisible" : false , "sClass" : "library_language" , "sWidth" : "125px" }, - /* Replay Gain */ { "sTitle" : $.i18n._("Replay Gain") , "mDataProp" : "replay_gain" , "bVisible" : false , "sClass" : "library_replay_gain" , "sWidth" : "80px" }, - /* Sample Rate */ { "sTitle" : $.i18n._("Sample Rate") , "mDataProp" : "sample_rate" , "bVisible" : false , "sClass" : "library_sr" , "sWidth" : "80px" }, - /* Track Number */ { "sTitle" : $.i18n._("Track Number") , "mDataProp" : "track_number" , "bVisible" : false , "sClass" : "library_track" , "sWidth" : "65px" }, + /* Owner */ { "sTitle" : $.i18n._("Owner") , "mDataProp" : "owner_id" , "bVisible" : false , "sClass" : "library_language" , "sWidth" : "125px" }, + /* Replay Gain */ { "sTitle" : $.i18n._("Replay Gain") , "mDataProp" : "replay_gain" , "bVisible" : false , "sClass" : "library_replay_gain" , "sWidth" : "80px" }, + /* Sample Rate */ { "sTitle" : $.i18n._("Sample Rate") , "mDataProp" : "sample_rate" , "bVisible" : false , "sClass" : "library_sr" , "sWidth" : "80px" }, + /* Track Number */ { "sTitle" : $.i18n._("Track Number") , "mDataProp" : "track_number" , "bVisible" : false , "sClass" : "library_track" , "sWidth" : "65px" }, /* Upload Time */ { "sTitle" : $.i18n._("Uploaded") , "mDataProp" : "utime" , "sClass" : "library_upload_time" , "sWidth" : "125px" } , /* Website */ { "sTitle" : $.i18n._("Website") , "mDataProp" : "info_url" , "bVisible" : false , "sClass" : "library_url" , "sWidth" : "150px" }, /* Year */ { "sTitle" : $.i18n._("Year") , "mDataProp" : "year" , "bVisible" : false , "sClass" : "library_year" , "sWidth" : "60px" } diff --git a/airtime_mvc/public/js/airtime/showbuilder/builder.js b/airtime_mvc/public/js/airtime/showbuilder/builder.js index d46d0aade..bb55faec7 100644 --- a/airtime_mvc/public/js/airtime/showbuilder/builder.js +++ b/airtime_mvc/public/js/airtime/showbuilder/builder.js @@ -214,7 +214,7 @@ var AIRTIME = (function(AIRTIME){ aData = [], i, length, $item; - + if (sNot !== undefined) { $selected = $selected.not("."+sNot); } @@ -1065,6 +1065,10 @@ var AIRTIME = (function(AIRTIME){ var elements = $sbTable.find('tr input:checked').parents('tr').not("."+NOW_PLAYING_CLASS); elements.hide(); + }, + stop: function() { + var elements = $sbTable.find('tr.'+SB_SELECTED_CLASS).not("."+NOW_PLAYING_CLASS); + elements.show(); } }; }()); diff --git a/airtime_mvc/public/js/airtime/showbuilder/builder_test.js b/airtime_mvc/public/js/airtime/showbuilder/builder_test.js new file mode 100644 index 000000000..38d521396 --- /dev/null +++ b/airtime_mvc/public/js/airtime/showbuilder/builder_test.js @@ -0,0 +1,1112 @@ +var AIRTIME = (function(AIRTIME){ + var mod, + oSchedTable, + SB_SELECTED_CLASS = "sb-selected", + CURSOR_SELECTED_CLASS = "cursor-selected-row", + NOW_PLAYING_CLASS = "sb-now-playing", + $sbContent, + $sbTable, + $toolbar, + $lib, + cursors = [], + cursorIds = [], + showInstanceIds = [], + headerFooter = [], + DISABLED_CLASS = 'ui-state-disabled', + $previouslySelected; + + if (AIRTIME.showbuilder === undefined) { + AIRTIME.showbuilder = {}; + } + mod = AIRTIME.showbuilder; + + function checkError(json) { + if (json.error !== undefined) { + alert(json.error); + } + } + + mod.timeout = undefined; + mod.timestamp = -1; + mod.showInstances = []; + + mod.resetTimestamp = function() { + + mod.timestamp = -1; + }; + + mod.setTimestamp = function(timestamp) { + + mod.timestamp = timestamp; + }; + + mod.updateCalendarStatusIcon = function(json) { + //make sure we are only executing this code on the calendar view, not + //the Now Playing view. + if (window.location.pathname.toLowerCase().indexOf("schedule") < 0) { + return; + } + + + var instance_id = json.schedule[0].instance; + + var lastElem = json.schedule[json.schedule.length-1]; + var $elem = $("#fc-show-instance-"+instance_id); + + //if the show is linked, then replace $elem to reference all linked + //instances + if ($elem.data("show-linked") == "1") { + var show_id = $elem.data("show-id"); + $elem = $('*[data-show-id="'+show_id+'"]'); + } + + $elem.find(".show-empty, .show-partial-filled").remove(); + if (json.schedule[1].empty) { + $elem + .find(".fc-event-inner") + .append(''); + } else if (lastElem["fRuntime"][0] == "-") { + $elem + .find(".fc-event-inner") + .append(''); + } + }; + + mod.getTimestamp = function() { + + if (mod.timestamp !== undefined) { + return mod.timestamp; + } + else { + return -1; + } + }; + + mod.setShowInstances = function(showInstances) { + mod.showInstances = showInstances; + }; + + mod.getShowInstances = function() { + return mod.showInstances; + }; + + mod.refresh = function(schedId) { + mod.resetTimestamp(); + + // once a track plays out we need to check if we can update + // the is_scheduled flag in cc_files + if (schedId > 0) { + $.post(baseUrl+"schedule/update-future-is-scheduled", + {"format": "json", "schedId": schedId}, function(data) { + if (data.redrawLibTable !== undefined && data.redrawLibTable) { + $("#library_content").find("#library_display").dataTable().fnStandingRedraw(); + } + }); + oSchedTable.fnDraw(); + } + }; + + mod.checkSelectButton = function() { + var $selectable = $sbTable.find("tr"); + + if ($selectable.length !== 0) { + AIRTIME.button.enableButton("btn-group #timeline-select", false); + } else { + AIRTIME.button.disableButton("btn-group #timeline-select", false); + } + + //need to check if the 'Select' button is disabled + var select = $(".btn-group #timeline-select"); + if (select.is(":disabled")) { + select.removeAttr("disabled"); + } + }; + + mod.checkTrimButton = function() { + var $over = $sbTable.find(".sb-over.sb-allowed"); + + if ($over.length !== 0) { + AIRTIME.button.enableButton("icon-cut", true); + } + else { + AIRTIME.button.disableButton("icon-cut", true); + } + }; + + mod.checkDeleteButton = function() { + var $selected = $sbTable.find("tr."+SB_SELECTED_CLASS); + + var button = $("#show_builder").find(".icon-trash").parent(); + if ($selected.length !== 0) { + button.removeClass(DISABLED_CLASS); + button.removeAttr('disabled'); + } else { + button.addClass(DISABLED_CLASS); + button.attr('disabled', 'disabled'); + } + }; + + mod.checkJumpToCurrentButton = function() { + var $current = $sbTable.find("."+NOW_PLAYING_CLASS); + + if ($current.length !== 0) { + AIRTIME.button.enableButton("icon-step-forward", true); + } + else { + AIRTIME.button.disableButton("icon-step-forward", true); + } + }; + + mod.checkCancelButton = function() { + + var $current = $sbTable.find(".sb-current-show"), + //this user type should be refactored into a separate users module later + //when there's more time and more JS will need to know user data. + userType = localStorage.getItem('user-type'), + canCancel = false; + + if ($current.length !== 0 && $current.hasClass("sb-allowed")) { + canCancel = true; + } + else if ($current.length !== 0 && (userType === 'A' || userType === 'P')) { + canCancel = true; + } + + if (canCancel === true) { + AIRTIME.button.enableButton("icon-ban-circle", true); + } + else { + AIRTIME.button.disableButton("icon-ban-circle", true); + } + }; + + mod.checkToolBarIcons = function() { + + //library may not be on the page. + if (AIRTIME.library !== undefined) { + AIRTIME.library.checkAddButton(); + } + + mod.checkSelectButton(); + mod.checkTrimButton(); + mod.checkDeleteButton(); + mod.checkJumpToCurrentButton(); + mod.checkCancelButton(); + }; + + mod.selectCursor = function($el) { + + $el.addClass(CURSOR_SELECTED_CLASS); + mod.checkToolBarIcons(); + }; + + mod.removeCursor = function($el) { + + $el.removeClass(CURSOR_SELECTED_CLASS); + mod.checkToolBarIcons(); + }; + + /* + * sNot is an optional string to filter selected elements by. (ex removing the currently playing item) + */ + mod.getSelectedData = function(sNot) { + var $selected = $sbTable.find("tr."+SB_SELECTED_CLASS), + aData = [], + i, length, + $item; + + if (sNot !== undefined) { + $selected = $selected.not("."+sNot); + } + + for (i = 0, length = $selected.length; i < length; i++) { + $item = $($selected.get(i)); + aData.push($item.data('aData')); + } + + return aData.reverse(); + }; + + mod.selectAll = function () { + var $trs = $sbTable.find("tr.lib-audio").not(".sb-past"); + $trs.addClass(SB_SELECTED_CLASS); + + mod.checkToolBarIcons(); + }; + + mod.selectNone = function () { + var $trs = $sbTable.find("tr.lib-audio"); + $trs.removeClass(SB_SELECTED_CLASS); + + mod.checkToolBarIcons(); + }; + + mod.disableUI = function() { + + $lib.block({ + message: "", + theme: true, + applyPlatformOpacityRules: false + }); + + $sbContent.block({ + message: "", + theme: true, + applyPlatformOpacityRules: false + }); + }; + + mod.enableUI = function() { + $lib.unblock(); + $sbContent.unblock(); + + //Block UI changes the postion to relative to display the messages. + $lib.css("position", "static"); + $sbContent.css("position", "static"); + }; + + mod.fnItemCallback = function(json) { + checkError(json); + + mod.getSelectedCursors(); + oSchedTable.fnDraw(); + + mod.enableUI(); + //Unneccessary reload of the library pane after moving tracks in the showbuilder pane. + //$("#library_content").find("#library_display").dataTable().fnStandingRedraw(); + }; + + mod.getSelectedCursors = function() { + cursorIds = []; + + /* We need to keep record of which show the cursor belongs to + * in the case where more than one show is displayed in the show builder + * because header and footer rows have the same id + */ + showInstanceIds = []; + + /* Keeps track if the row is a footer. We need to do this because + * header and footer rows have the save cursorIds and showInstanceId + * so both will be selected in the draw callback + */ + headerFooter = []; + + cursors = $(".cursor-selected-row"); + for (i = 0; i < cursors.length; i++) { + cursorIds.push(($(cursors.get(i)).attr("id"))); + showInstanceIds.push(($(cursors.get(i)).attr("si_id"))); + if ($(cursors.get(i)).hasClass("sb-footer")) { + headerFooter.push("f"); + } else { + headerFooter.push("n"); + } + } + }; + + mod.fnAdd = function(aMediaIds, aSchedIds) { + mod.disableUI(); + for (var i in aSchedIds) { + if ($("#"+aSchedIds[i].id).hasClass("sb-past")) { + alert($.i18n._("Cannot add media before currently playing track.")); + mod.enableUI(); + return; + } + } + + $.post(baseUrl+"showbuilder/schedule-add", + {"format": "json", "mediaIds": aMediaIds, "schedIds": aSchedIds}, + mod.fnItemCallback + ); + }; + + mod.fnMove = function(aSelect, aAfter) { + + mod.disableUI(); + + $.post(baseUrl+"showbuilder/schedule-move", + {"format": "json", "selectedItem": aSelect, "afterItem": aAfter}, + mod.fnItemCallback + ); + }; + + mod.fnRemove = function(aItems) { + + mod.disableUI(); + if (confirm($.i18n._("Delete selected item(s)?"))) { + $.post( baseUrl+"showbuilder/schedule-remove", + {"items": aItems, "format": "json"}, + mod.fnItemCallback + ); + }else{ + mod.enableUI(); + } + }; + + mod.fnRemoveSelectedItems = function() { + var aData = mod.getSelectedData(), + i, + length, + temp, + aItems = []; + + for (i=0, length = aData.length; i < length; i++) { + temp = aData[i]; + aItems.push({"id": temp.id, "instance": temp.instance, "timestamp": temp.timestamp}); + } + + mod.fnRemove(aItems); + }; + + mod.fnServerData = function fnBuilderServerData( sSource, aoData, fnCallback ) { + + aoData.push( { name: "timestamp", value: mod.getTimestamp()} ); + aoData.push( { name: "instances", value: mod.getShowInstances()} ); + aoData.push( { name: "format", value: "json"} ); + + if (mod.fnServerData.hasOwnProperty("start")) { + aoData.push( { name: "start", value: mod.fnServerData.start} ); + } + if (mod.fnServerData.hasOwnProperty("end")) { + aoData.push( { name: "end", value: mod.fnServerData.end} ); + } + if (mod.fnServerData.hasOwnProperty("ops")) { + aoData.push( { name: "myShows", value: mod.fnServerData.ops.myShows} ); + aoData.push( { name: "showFilter", value: mod.fnServerData.ops.showFilter} ); + aoData.push( { name: "showInstanceFilter", value: mod.fnServerData.ops.showInstanceFilter} ); + } + + $.ajax({ + "dataType": "json", + "type": "POST", + "url": sSource, + "data": aoData, + "success": function(json) { + mod.updateCalendarStatusIcon(json) + mod.setTimestamp(json.timestamp); + mod.setShowInstances(json.instances); + mod.getSelectedCursors(); + fnCallback(json); + } + }); + }; + + mod.jumpToCurrentTrack = function() { + var $scroll = $sbContent.find(".dataTables_scrolling"); + var scrolled = $scroll.scrollTop(); + var scrollingTop = $scroll.offset().top; + var current = $sbTable.find("."+NOW_PLAYING_CLASS); + var currentTop = current.offset().top; + + $scroll.scrollTop(currentTop - scrollingTop + scrolled); + }; + + mod.builderDataTable = function() { + $sbContent = $('#show_builder'); + $lib = $("#library_content"), + $sbTable = $sbContent.find('table'); + var isInitialized = false; + + var lockedPreviewIcon = document.createElement('span'); + lockedPreviewIcon.setAttribute('class', 'ui-icon ui-icon-locked'); + var previewIcon = document.createElement('img'); + previewIcon.setAttribute('src', baseUrl+'css/images/icon_audioclip.png'); + previewIcon.setAttribute('title', $.i18n._("Track preview")); + + oSchedTable = $sbTable.dataTable( { + "aoColumns": [ + /* Type */ {"mDataProp": "image", "sTitle": "", "sClass": "library_image sb-image", "sWidth": "16px"}, + /* starts */ {"mDataProp": "starts", "sTitle": $.i18n._("Start"), "sClass": "sb-starts", "sWidth": "60px"}, + /* ends */ {"mDataProp": "ends", "sTitle": $.i18n._("End"), "sClass": "sb-ends", "sWidth": "60px"}, + /* runtime */ {"mDataProp": "runtime", "sTitle": $.i18n._("Duration"), "sClass": "library_length sb-length", "sWidth": "65px"}, + /* title */ {"mDataProp": "title", "sTitle": $.i18n._("Title"), "sClass": "sb-title"}, + /* creator */ {"mDataProp": "creator", "sTitle": $.i18n._("Creator"), "sClass": "sb-creator"}, + /* album */ {"mDataProp": "album", "sTitle": $.i18n._("Album"), "sClass": "sb-album"}, + /* cue in */ {"mDataProp": "cuein", "sTitle": $.i18n._("Cue In"), "bVisible": false, "sClass": "sb-cue-in"}, + /* cue out */ {"mDataProp": "cueout", "sTitle": $.i18n._("Cue Out"), "bVisible": false, "sClass": "sb-cue-out"}, + /* fade in */ {"mDataProp": "fadein", "sTitle": $.i18n._("Fade In"), "bVisible": false, "sClass": "sb-fade-in"}, + /* fade out */ {"mDataProp": "fadeout", "sTitle": $.i18n._("Fade Out"), "bVisible": false, "sClass": "sb-fade-out"}, + /* Mime */ {"mDataProp" : "mime", "sTitle" : $.i18n._("Mime"), "bVisible": false, "sClass": "sb-mime"} + ], + + "bJQueryUI": true, + "bSort": false, + "bFilter": false, + "bProcessing": true, + "bServerSide": true, + "bInfo": false, + "bAutoWidth": false, + "bDeferRender": true, + + "bStateSave": true, + "fnStateSaveParams": function (oSettings, oData) { + //remove oData components we don't want to save. + delete oData.oSearch; + delete oData.aoSearchCols; + }, + "fnStateSave": function fnStateSave(oSettings, oData) { + localStorage.setItem('datatables-timeline', JSON.stringify(oData)); + }, + "fnStateLoad": function fnBuilderStateLoad(oSettings) { + var settings = localStorage.getItem('datatables-timeline'); + + if (settings !== "") { + return JSON.parse(settings); + } + }, + "fnStateLoadParams": function (oSettings, oData) { + var i, + length, + a = oData.abVisCols; + + //putting serialized data back into the correct js type to make + //sure everything works properly. + for (i = 0, length = a.length; i < length; i++) { + if (typeof(a[i]) === "string") { + a[i] = (a[i] === "true") ? true : false; + } + } + + oData.iCreate = parseInt(oData.iCreate, 10); + }, + + "fnServerData": mod.fnServerData, + "fnRowCallback": function fnRowCallback( nRow, aData, iDisplayIndex, iDisplayIndexFull ) { + var i, length, + sSeparatorHTML, + fnPrepareSeparatorRow, + $node, + cl="", + //background-color to imitate calendar color. + r,g,b,a, + $nRow = $(nRow), + $image, + $div, + headerIcon; + + fnPrepareSeparatorRow = function fnPrepareSeparatorRow(sRowContent, sClass, iNodeIndex) { + //Albert: + //$(nRow.children[iNodeIndex]).replaceWith(emptyNode); + + $node = $(nRow.children[iNodeIndex]); + $node.html(sRowContent); + + $node.attr('colspan',100); + for (i = iNodeIndex + 1, length = nRow.children.length; i < length; i = i+1) { + $node = $(nRow.children[i]); + $node.html(""); + $node.attr("style", "display : none"); + } + + $nRow.addClass(sClass); + + }; + + if (aData.header === true) { + //remove the column classes from all tds. + $nRow.find('td').removeClass(); + + $node = $(nRow.children[0]); + $node.html(""); + cl = 'sb-header'; + + if (aData.record === true) { + $div = $("
", { + "class": "small-icon " + headerIcon + }); + $node.append($div); + } + else if (aData.rebroadcast === true) { + $div = $("
", { + "class": "small-icon rebroadcast" + }); + $node.append($div); + } + + sSeparatorHTML = ''+aData.title+''; + + if (aData.rebroadcast === true) { + sSeparatorHTML += ''+aData.rebroadcast_title+''; + } + + sSeparatorHTML += ''; + + if (aData.startDate === aData.endDate) { + sSeparatorHTML += ''+aData.startDate+''+aData.startTime+''; + sSeparatorHTML +='-'+aData.endTime+''; + } + else { + sSeparatorHTML += ''+aData.startDate+''+aData.startTime+''; + sSeparatorHTML +='-'+aData.endDate+''+aData.endTime+''; + } + + sSeparatorHTML += ''; + + fnPrepareSeparatorRow(sSeparatorHTML, cl, 1); + } + else if (aData.footer === true) { + //remove the column classes from all tds. + $nRow.find('td').removeClass(); + + $node = $(nRow.children[0]); + cl = 'sb-footer'; + + //check the show's content status. + if (aData.runtime >= 0) { + $node.html(''); + cl = cl + ' ui-state-highlight'; + } + else { + $node.html(''); + cl = cl + ' ui-state-error'; + } + + sSeparatorHTML = ''+aData.fRuntime+''; + fnPrepareSeparatorRow(sSeparatorHTML, cl, 1); + } + else if (aData.empty === true) { + //remove the column classes from all tds. + $nRow.find('td').removeClass(); + + $node = $(nRow.children[0]); + if ($node) { + $node.empty(); + } + + sSeparatorHTML = ''+$.i18n._("Show Empty")+''; + cl = cl + " sb-empty odd"; + + fnPrepareSeparatorRow(sSeparatorHTML, cl, 1); + } + else if (aData.record === true) { + //remove the column classes from all tds. + $nRow.find('td').removeClass(); + + $node = $(nRow.children[0]); + $node.html(''); + + sSeparatorHTML = ''+$.i18n._("Recording From Line In")+''; + cl = cl + " sb-record odd"; + fnPrepareSeparatorRow(sSeparatorHTML, cl, 1); + } + else { + + //add the play function if the file exists on disk. + $image = $nRow.find('td.sb-image'); + $image.empty(); + //check if the file exists. + if (aData.image === true) { + $nRow.addClass("lib-audio"); + if (!isAudioSupported(aData.mime)) { + //$image.html(''); + $image.append(lockedPreviewIcon); + } else { + $image.append(previewIcon.cloneNode(false)); + $image.click(function() { + open_show_preview(aData.instance, aData.pos); + return false; + }); + + } + } + else { + $image.html(''); + $image.find(".ui-icon-alert").qtip({ + content: { + text: $.i18n._("Airtime is unsure about the status of this file. This can happen when the file is on a remote drive that is unaccessible or the file is in a directory that isn't \"watched\" anymore.") + }, + style: { + classes: "ui-tooltip-dark" + }, + show: 'mouseover', + hide: 'mouseout' + }); + } + } + + //add the show colour to the leftmost td + if (aData.footer !== true) { + + if ($nRow.hasClass('sb-header')) { + a = 1; + } + else if ($nRow.hasClass('odd')) { + a = 0.3; + } + else if ($nRow.hasClass('even')) { + a = 0.4; + } + + //convert from hex to rgb. + r = parseInt((aData.backgroundColor).substring(0,2), 16); + g = parseInt((aData.backgroundColor).substring(2,4), 16); + b = parseInt((aData.backgroundColor).substring(4,6), 16); + + $nRow.find('td:first').css('background', 'rgba('+r+', '+g+', '+b+', '+a+')'); + } + + //save some info for reordering purposes. + $nRow.data({"aData": aData}); + + if (aData.scheduled === 1) { + $nRow.addClass(NOW_PLAYING_CLASS); + } + else if (aData.scheduled === 0) { + $nRow.addClass("sb-past"); + } + else { + $nRow.addClass("sb-future"); + } + + if (aData.allowed !== true || aData.linked_allowed === false) { + $nRow.addClass("sb-not-allowed"); + } + else { + $nRow.addClass("sb-allowed"); + $nRow.attr("id", aData.id); + $nRow.attr("si_id", aData.instance); + } + + //status used to colour tracks. + if (aData.status === 2) { + $nRow.addClass("sb-boundry"); + } + else if (aData.status === 0) { + $nRow.addClass("sb-over"); + } + + if (aData.currentShow === true) { + $nRow.addClass("sb-current-show"); + } + }, + //remove any selected nodes before the draw. + "fnPreDrawCallback": function( oSettings ) { + + //make sure any dragging helpers are removed or else they'll be stranded on the screen. + $("#draggingContainer").remove(); + }, + "fnDrawCallback": function fnBuilderDrawCallback(oSettings, json) { + + if (!isInitialized) { + //when coming to 'Now Playing' page we want the page + //to jump to the current track + if ($(this).find("."+NOW_PLAYING_CLASS).length > 0) { + mod.jumpToCurrentTrack(); + } + } + + isInitialized = true; + var aData, + elements, + i, length, temp; + + clearTimeout(mod.timeout); + + //order of importance of elements for setting the next timeout. + elements = [ + $sbTable.find("tr."+NOW_PLAYING_CLASS), + $sbTable.find("tbody").find("tr.sb-future.sb-footer, tr.sb-future.sb-header").filter(":first") + ]; + + //check which element we should set a timeout relative to. + for (i = 0, length = elements.length; i < length; i++) { + temp = elements[i]; + + if (temp.length > 0) { + aData = temp.data("aData"); + // max time interval + // setTimeout allows only up to (2^31)-1 millisecs timeout value + maxRefreshInterval = Math.pow(2, 31) - 1; + refreshInterval = aData.refresh * 1000; + if(refreshInterval > maxRefreshInterval){ + refreshInterval = maxRefreshInterval; + } + mod.timeout = setTimeout(function() {mod.refresh(aData.id)}, refreshInterval); //need refresh in milliseconds + break; + } + } + + + mod.checkToolBarIcons(); + }, + + // R = ColReorder, C = ColVis + "sDom": 'R<"dt-process-rel"r><"sb-padded"<"H"C>><"dataTables_scrolling sb-padded"t>', + + "oColVis": { + "aiExclude": [ 0, 1 ], + "buttonText": $.i18n._("Show / hide columns"), + }, + + "oColReorder": { + "iFixedColumns": 2 + }, + + "sAjaxDataProp": "schedule", + "oLanguage": datatables_dict, + "sAjaxSource": baseUrl+"showbuilder/builder-feed" + }); + + $sbTable.find("tbody").on("click", "tr:not(.sb-past)", function(ev) { + + var $tr = $(this), + // Get the ID of the selected row + $rowId = $tr.attr("id"); + + if (ev.shiftKey && $previouslySelected !== undefined) { + if ($previouslySelected.attr("id") == $rowId) { + return; + } + + // If the selected row comes before the previously selected row, + // we want to select previous rows, otherwise we select next + if ($previouslySelected.prevAll("#"+$rowId).length !== 0) { + $previouslySelected.prevUntil($tr).each(function(i, el){ + $(el).addClass(SB_SELECTED_CLASS); + }); + } else { + $previouslySelected.nextUntil($tr).each(function(i, el){ + $(el).addClass(SB_SELECTED_CLASS); + }); + } + $tr.addClass(SB_SELECTED_CLASS); + } else if (ev.ctrlKey && $previouslySelected !== undefined) { + $tr.addClass(SB_SELECTED_CLASS); + } else { + $("."+SB_SELECTED_CLASS).removeClass(SB_SELECTED_CLASS); + $tr.addClass(SB_SELECTED_CLASS); + } + + // Remember this row so we can properly multiselect + $previouslySelected = $tr; + + mod.checkToolBarIcons(); + }); + + var sortableConf = (function(){ + var origTrs, + aItemData = [], + oPrevData, + fnAdd, + fnMove, + fnReceive, + fnUpdate, + i, + html, + helperData, + draggingContainer; + + fnAdd = function() { + var aMediaIds = [], + aSchedIds = []; + + for(i = 0; i < aItemData.length; i++) { + aMediaIds.push({"id": aItemData[i].id, "type": aItemData[i].ftype}); + } + aSchedIds.push({"id": oPrevData.id, "instance": oPrevData.instance, "timestamp": oPrevData.timestamp}); + + mod.fnAdd(aMediaIds, aSchedIds); + }; + + fnMove = function() { + var aSelect = [], + aAfter = []; + + for(i = 0; i < helperData.length; i++) { + aSelect.push({"id": helperData[i].id, "instance": helperData[i].instance, "timestamp": helperData[i].timestamp}); + } + + aAfter.push({"id": oPrevData.id, "instance": oPrevData.instance, "timestamp": oPrevData.timestamp}); + + mod.fnMove(aSelect, aAfter); + }; + + fnReceive = function(event, ui) { + var aItems = []; + + AIRTIME.library.addToChosen(ui.item); + + aItems = AIRTIME.library.getSelectedData(); + origTrs = aItems; + html = ui.helper.html(); + + AIRTIME.library.removeFromChosen(ui.item); + }; + + fnUpdate = function(event, ui) { + var prev = ui.item.prev(); + + //can't add items outside of shows. + if (prev.find("td:first").hasClass("dataTables_empty") + || prev.length === 0) { + alert($.i18n._("Cannot schedule outside a show.")); + ui.item.remove(); + return; + } + + //if item is added after a footer, add the item after the last item in the show. + if (prev.hasClass("sb-footer")) { + prev = prev.prev(); + } + + aItemData = []; + oPrevData = prev.data("aData"); + + //item was dragged in + if (origTrs !== undefined) { + + $sbTable.find("tr.ui-draggable") + .empty() + .after(html); + + aItemData = origTrs; + origTrs = undefined; + fnAdd(); + } + //item was reordered. + else { + + //ui.item + // .empty() + // .after(draggingContainer.html()); + + aItemData.push(ui.item.data("aData")); + fnMove(); + } + }; + + return { + placeholder: "sb-placeholder ui-state-highlight", + //forcePlaceholderSize: true, + distance: 10, + helper: + function(event, item) { + var selected = mod.getSelectedData(NOW_PLAYING_CLASS), + thead = $("#show_builder_table thead"), + colspan = thead.find("th").length, + trfirst = thead.find("tr:first"), + width = trfirst.width(), + height = trfirst.height(), + message; + + //if nothing is checked select the dragged item. + if (selected.length === 0) { + selected = [item.data("aData")]; + } + + if (selected.length === 1) { + message = sprintf($.i18n._("Moving %s"), selected[0].title); + //draggingContainer = item; //Default DataTables drag and drop + draggingContainer = $('') + .addClass('sb-helper') + .append('') + .find("td") + .attr("colspan", colspan) + .width(width) + .height(height) + .addClass("ui-state-highlight") + .append(message) + .end(); + } + else { + message = sprintf($.i18n._("Moving %s Items"), selected.length); + draggingContainer = $('') + .addClass('sb-helper') + .append('') + .find("td") + .attr("colspan", colspan) + .width(width) + .height(height) + .addClass("ui-state-highlight") + .append(message) + .end(); + + } + + helperData = selected; + + return draggingContainer; + }, + items: 'tr:not(:first, :last, .sb-header, .sb-not-allowed, .sb-past, .sb-now-playing, .sb-empty)', + cancel: '.sb-footer', + receive: fnReceive, + update: fnUpdate, + start: function(event, ui) { + var elements = $sbTable.find('tr.'+SB_SELECTED_CLASS).not("."+NOW_PLAYING_CLASS); + elements.hide(); + }, + stop: function() { + var elements = $sbTable.find('tr.'+SB_SELECTED_CLASS).not("."+NOW_PLAYING_CLASS); + elements.show(); + } + }; + }()); + + $sbTable.sortable(sortableConf); + + //start setup of the builder toolbar. + $toolbar = $(".sb-content .fg-toolbar"); + + $menu = $("
"); + $menu.append("
" + + "" + + "" + + "
") + .append("
" + + "
") + .append("
" + + "
"); + + //if 'Add/Remove content' was chosen from the context menu + //in the Calendar do not append these buttons + if ($(".ui-dialog-content").length === 0) { + $menu.append("
" + + "
") + .append("
" + + "
"); + } + + if (localStorage.getItem('user-type') != 'G') { + $toolbar.append($menu); + } + + $menu = undefined; + + $('#timeline-sa').click(function(){mod.selectAll();}); + $('#timeline-sn').click(function(){mod.selectNone();}); + + //cancel current show + $toolbar.find('.icon-ban-circle').parent() + .click(function() { + var $tr, + data, + msg = $.i18n._('Cancel Current Show?'); + + if (AIRTIME.button.isDisabled('icon-ban-circle', true) === true) { + return; + } + + $tr = $sbTable.find('tr.sb-future:first'); + + if ($tr.hasClass('sb-current-show')) { + data = $tr.data("aData"); + + if (data.record === true) { + msg = $.i18n._('Stop recording current show?'); + } + + if (confirm(msg)) { + var url = baseUrl+"Schedule/cancel-current-show"; + $.ajax({ + url: url, + data: {format: "json", id: data.instance}, + success: function(data){ + $("#library_content").find("#library_display").dataTable().fnStandingRedraw(); + var oTable = $sbTable.dataTable(); + oTable.fnDraw(); + } + }); + } + } + }); + + //jump to current + $toolbar.find('.icon-step-forward').parent() + .click(function() { + + if (AIRTIME.button.isDisabled('icon-step-forward', true) === true) { + return; + } + /* + var $scroll = $sbContent.find(".dataTables_scrolling"), + scrolled = $scroll.scrollTop(), + scrollingTop = $scroll.offset().top, + current = $sbTable.find("."+NOW_PLAYING_CLASS), + currentTop = current.offset().top; + + $scroll.scrollTop(currentTop - scrollingTop + scrolled); + */ + mod.jumpToCurrentTrack(); + }); + + //delete overbooked tracks. + $toolbar.find('.icon-cut', true).parent() + .click(function() { + + if (AIRTIME.button.isDisabled('icon-cut', true) === true) { + return; + } + + var temp, + aItems = [], + trs = $sbTable.find(".sb-over.sb-future.sb-allowed"); + + trs.each(function(){ + temp = $(this).data("aData"); + aItems.push({"id": temp.id, "instance": temp.instance, "timestamp": temp.timestamp}); + }); + + mod.fnRemove(aItems); + }); + + //delete selected tracks + $toolbar.find('.icon-trash').parent() + .click(function() { + + var button = $("#show_builder").find(".icon-trash").parent(); + + if (button.hasClass(DISABLED_CLASS)) { + return; + } + + mod.fnRemoveSelectedItems(); + }); + + //add events to cursors. + $sbTable.find("tbody").on("click", "div.marker", function(event) { + var $tr = $(this).parents("tr"), + $trs; + + if ($tr.hasClass(CURSOR_SELECTED_CLASS)) { + mod.removeCursor($tr); + } + else { + mod.selectCursor($tr); + } + + if (event.ctrlKey === false) { + $trs = $sbTable.find('.'+CURSOR_SELECTED_CLASS).not($tr); + mod.removeCursor($trs); + } + + return false; + }); + + /* + * Select button dropdown state in the toolbar. + * The button has to be disabled to prevent the dropdown + * from opening + */ + $sbContent.on("mouseenter", ".btn-group #timeline-select", function(ev) { + $el = $(this); + + if ($el.hasClass("ui-state-disabled")) { + $el.attr("disabled", "disabled"); + } + else { + $el.removeAttr("disabled"); + } + }); + }; + + return AIRTIME; + +}(AIRTIME || {})); diff --git a/airtime_mvc/public/js/airtime/showbuilder/main_builder_test.js b/airtime_mvc/public/js/airtime/showbuilder/main_builder_test.js new file mode 100644 index 000000000..1da573d13 --- /dev/null +++ b/airtime_mvc/public/js/airtime/showbuilder/main_builder_test.js @@ -0,0 +1,347 @@ +AIRTIME = (function(AIRTIME) { + + var viewport, + $lib, + $libWrapper, + $builder, + $fs, + widgetHeight, + screenWidth, + resizeTimeout, + oBaseDatePickerSettings, + oBaseTimePickerSettings, + oRange, + dateStartId = "#sb_date_start", + timeStartId = "#sb_time_start", + dateEndId = "#sb_date_end", + timeEndId = "#sb_time_end", + mod; + + if (AIRTIME.builderMain === undefined) { + AIRTIME.builderMain = {}; + } + mod = AIRTIME.builderMain; + + oBaseDatePickerSettings = { + dateFormat: 'yy-mm-dd', + //i18n_months, i18n_days_short are in common.js + monthNames: i18n_months, + dayNamesMin: i18n_days_short, + onClick: function(sDate, oDatePicker) { + $(this).datepicker( "setDate", sDate ); + }, + onClose: validateTimeRange + }; + + oBaseTimePickerSettings = { + showPeriodLabels: false, + showCloseButton: true, + closeButtonText: $.i18n._("Done"), + showLeadingZero: false, + defaultTime: '0:00', + hourText: $.i18n._("Hour"), + minuteText: $.i18n._("Minute"), + onClose: validateTimeRange + }; + + function setWidgetSize() { + viewport = AIRTIME.utilities.findViewportDimensions(); + widgetHeight = viewport.height - 180; + screenWidth = Math.floor(viewport.width - 50); + + var libTableHeight = widgetHeight - 175, + builderTableHeight = widgetHeight - 95, + oTable; + + if ($fs.is(':visible')) { + builderTableHeight = builderTableHeight - 40; + } + + //set the heights of the main widgets. + $builder//.height(widgetHeight) + .find(".dataTables_scrolling") + .css("max-height", builderTableHeight) + .end(); + //.width(screenWidth); + + $lib//.height(widgetHeight) + .find(".dataTables_scrolling") + .css("max-height", libTableHeight) + .end(); + + if ($lib.filter(':visible').length > 0) { + + //$lib.width(Math.floor(screenWidth * 0.47)); + + $builder//.width(Math.floor(screenWidth * 0.47)) + .find("#sb_edit") + .remove() + .end() + .find("#sb_date_start") + .css("margin-left", 0) + .end(); + + oTable = $('#show_builder_table').dataTable(); + //oTable.fnDraw(); + } + } + + function validateTimeRange() { + var oRange, + inputs = $('.sb-timerange > input'), + start, end; + + oRange = AIRTIME.utilities.fnGetScheduleRange(dateStartId, timeStartId, dateEndId, timeEndId); + + start = oRange.start; + end = oRange.end; + + if (end >= start) { + inputs.removeClass('error'); + } + else { + if (!inputs.hasClass('error')) { + inputs.addClass('error'); + } + } + + return { + start: start, + end: end, + isValid: end >= start + }; + } + + function showSearchSubmit() { + var fn, + op, + oTable = $('#show_builder_table').dataTable(), + check; + + check = validateTimeRange(); + + if (check.isValid) { + + //reset timestamp value since input values could have changed. + AIRTIME.showbuilder.resetTimestamp(); + + fn = oTable.fnSettings().fnServerData; + fn.start = check.start; + fn.end = check.end; + + op = $("div.sb-advanced-options"); + if (op.is(":visible")) { + + if (fn.ops === undefined) { + fn.ops = {}; + } + fn.ops.showFilter = op.find("#sb_show_filter").val(); + fn.ops.myShows = op.find("#sb_my_shows").is(":checked") ? 1 : 0; + } + + oTable.fnDraw(); + } + } + + mod.onReady = function() { + + Dropzone.options.uploadForm = { + init: function () { + this.on("sending", function (file, xhr, data) { + data.append("csrf_token", $("#csrf").val()); + }); + } + }; + + // define module vars. + $lib = $("#library_content"); + $builder = $("#show_builder"); + $fs = $builder.find('fieldset'); + + /* + * Icon hover states for search. + */ + $builder.on("mouseenter", ".sb-timerange .ui-button", function(ev) { + $(this).addClass("ui-state-hover"); + }); + $builder.on("mouseleave", ".sb-timerange .ui-button", function(ev) { + $(this).removeClass("ui-state-hover"); + }); + + $builder.find(dateStartId) + .datepicker(oBaseDatePickerSettings) + .blur(validateTimeRange); + + $builder.find(timeStartId) + .timepicker(oBaseTimePickerSettings) + .blur(validateTimeRange); + + $builder.find(dateEndId) + .datepicker(oBaseDatePickerSettings) + .blur(validateTimeRange); + + $builder.find(timeEndId) + .timepicker(oBaseTimePickerSettings) + .blur(validateTimeRange); + + + oRange = AIRTIME.utilities.fnGetScheduleRange(dateStartId, timeStartId, + dateEndId, timeEndId); + AIRTIME.showbuilder.fnServerData.start = oRange.start; + AIRTIME.showbuilder.fnServerData.end = oRange.end; + + //the user might not have the library on the page (guest user) + if (AIRTIME.library !== undefined) { + AIRTIME.library.libraryInit(); + } + + AIRTIME.showbuilder.builderDataTable(); + setWidgetSize(); + + $libWrapper = $lib.find("#library_display_wrapper"); + $builder.find('.dataTables_scrolling').css("max-height", + widgetHeight - 95); + + $builder.on("click", "#sb_submit", showSearchSubmit); + + $builder.on("click", "#sb_edit", function(ev) { + var schedTable = $("#show_builder_table").dataTable(); + + // reset timestamp to redraw the cursors. + AIRTIME.showbuilder.resetTimestamp(); + + $lib.show().width(Math.floor(screenWidth * 0.48)); + + $builder.width(Math.floor(screenWidth * 0.48)).find("#sb_edit") + .remove().end().find("#sb_date_start") + .css("margin-left", 0).end(); + + schedTable.fnDraw(); + + $.ajax( { + url : baseUrl+"usersettings/set-now-playing-screen-settings", + type : "POST", + data : { + settings : { + library : true + }, + format : "json" + }, + dataType : "json", + success : function() { + } + }); + }); + + $lib.on("click", "#sb_lib_close", function() { + var schedTable = $("#show_builder_table").dataTable(); + + $lib.hide(); + $builder.width(screenWidth).find(".sb-timerange").find("#sb_date_start").css("margin-left", 30) + .end().end(); + + schedTable.fnDraw(); + + $.ajax( { + url : baseUrl+"usersettings/set-now-playing-screen-settings", + type : "POST", + data : { + settings : { + library : false + }, + format : "json" + }, + dataType : "json", + success : function() { + } + }); + }); + + $builder.find('legend').click( + function(ev, item) { + + if ($fs.hasClass("closed")) { + + $fs.removeClass("closed"); + $builder.find('.dataTables_scrolling').css( + "max-height", widgetHeight - 150); + } else { + $fs.addClass("closed"); + + // set defaults for the options. + $fs.find('select').val(0); + $fs.find('input[type="checkbox"]').attr("checked", + false); + $builder.find('.dataTables_scrolling').css( + "max-height", widgetHeight - 110); + } + }); + + // set click event for all my shows checkbox. + $builder.on("click", "#sb_my_shows", function(ev) { + + if ($(this).is(':checked')) { + $(ev.delegateTarget).find('#sb_show_filter').val(0); + } + + showSearchSubmit(); + }); + + //set select event for choosing a show. + $builder.on("change", '#sb_show_filter', function(ev) { + + if ($(this).val() !== 0) { + $(ev.delegateTarget).find('#sb_my_shows') + .attr("checked", false); + } + + showSearchSubmit(); + + }); + + function checkScheduleUpdates() { + 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(); + data["instances"] = AIRTIME.showbuilder.getShowInstances(); + + if (fn.hasOwnProperty("ops")) { + data["myShows"] = fn.ops.myShows; + data["showFilter"] = fn.ops.showFilter; + data["showInstanceFilter"] = fn.ops.showInstanceFilter; + } + + $.ajax( { + "dataType" : "json", + "type" : "GET", + "url" : baseUrl+"showbuilder/check-builder-feed", + "data" : data, + "success" : function(json) { + if (json.update === true) { + oTable.fnDraw(); + } + setTimeout(checkScheduleUpdates, 5000); + } + }); + + //check if the timeline view needs updating. + setTimeout(checkScheduleUpdates, 5000); + } + }; + + mod.onResize = function() { + + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(setWidgetSize, 100); + }; + + return AIRTIME; + +} (AIRTIME || {})); + +$(document).ready(AIRTIME.builderMain.onReady); +$(window).resize(AIRTIME.builderMain.onResize); diff --git a/airtime_mvc/public/js/libs/dropzone.min.js b/airtime_mvc/public/js/libs/dropzone.min.js new file mode 100644 index 000000000..56f769591 --- /dev/null +++ b/airtime_mvc/public/js/libs/dropzone.min.js @@ -0,0 +1,2 @@ +(function(){var a,b,c,d,e,f,g,h,i=[].slice,j={}.hasOwnProperty,k=function(a,b){function c(){this.constructor=a}for(var d in b)j.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a};g=function(){},b=function(){function a(){}return a.prototype.addEventListener=a.prototype.on,a.prototype.on=function(a,b){return this._callbacks=this._callbacks||{},this._callbacks[a]||(this._callbacks[a]=[]),this._callbacks[a].push(b),this},a.prototype.emit=function(){var a,b,c,d,e,f;if(d=arguments[0],a=2<=arguments.length?i.call(arguments,1):[],this._callbacks=this._callbacks||{},c=this._callbacks[d])for(e=0,f=c.length;f>e;e++)b=c[e],b.apply(this,a);return this},a.prototype.removeListener=a.prototype.off,a.prototype.removeAllListeners=a.prototype.off,a.prototype.removeEventListener=a.prototype.off,a.prototype.off=function(a,b){var c,d,e,f,g;if(!this._callbacks||0===arguments.length)return this._callbacks={},this;if(d=this._callbacks[a],!d)return this;if(1===arguments.length)return delete this._callbacks[a],this;for(e=f=0,g=d.length;g>f;e=++f)if(c=d[e],c===b){d.splice(e,1);break}return this},a}(),a=function(a){function c(a,b){var e,f,g;if(this.element=a,this.version=c.version,this.defaultOptions.previewTemplate=this.defaultOptions.previewTemplate.replace(/\n*/g,""),this.clickableElements=[],this.listeners=[],this.files=[],"string"==typeof this.element&&(this.element=document.querySelector(this.element)),!this.element||null==this.element.nodeType)throw new Error("Invalid dropzone element.");if(this.element.dropzone)throw new Error("Dropzone already attached.");if(c.instances.push(this),this.element.dropzone=this,e=null!=(g=c.optionsForElement(this.element))?g:{},this.options=d({},this.defaultOptions,e,null!=b?b:{}),this.options.forceFallback||!c.isBrowserSupported())return this.options.fallback.call(this);if(null==this.options.url&&(this.options.url=this.element.getAttribute("action")),!this.options.url)throw new Error("No URL provided.");if(this.options.acceptedFiles&&this.options.acceptedMimeTypes)throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated.");this.options.acceptedMimeTypes&&(this.options.acceptedFiles=this.options.acceptedMimeTypes,delete this.options.acceptedMimeTypes),this.options.method=this.options.method.toUpperCase(),(f=this.getExistingFallback())&&f.parentNode&&f.parentNode.removeChild(f),this.options.previewsContainer!==!1&&(this.previewsContainer=this.options.previewsContainer?c.getElement(this.options.previewsContainer,"previewsContainer"):this.element),this.options.clickable&&(this.clickableElements=this.options.clickable===!0?[this.element]:c.getElements(this.options.clickable,"clickable")),this.init()}var d,e;return k(c,a),c.prototype.Emitter=b,c.prototype.events=["drop","dragstart","dragend","dragenter","dragover","dragleave","addedfile","removedfile","thumbnail","error","errormultiple","processing","processingmultiple","uploadprogress","totaluploadprogress","sending","sendingmultiple","success","successmultiple","canceled","canceledmultiple","complete","completemultiple","reset","maxfilesexceeded","maxfilesreached","queuecomplete"],c.prototype.defaultOptions={url:null,method:"post",withCredentials:!1,parallelUploads:2,uploadMultiple:!1,maxFilesize:256,paramName:"file",createImageThumbnails:!0,maxThumbnailFilesize:10,thumbnailWidth:120,thumbnailHeight:120,filesizeBase:1e3,maxFiles:null,filesizeBase:1e3,params:{},clickable:!0,ignoreHiddenFiles:!0,acceptedFiles:null,acceptedMimeTypes:null,autoProcessQueue:!0,autoQueue:!0,addRemoveLinks:!1,previewsContainer:null,capture:null,dictDefaultMessage:"Drop files here to upload",dictFallbackMessage:"Your browser does not support drag'n'drop file uploads.",dictFallbackText:"Please use the fallback form below to upload your files like in the olden days.",dictFileTooBig:"File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.",dictInvalidFileType:"You can't upload files of this type.",dictResponseError:"Server responded with {{statusCode}} code.",dictCancelUpload:"Cancel upload",dictCancelUploadConfirmation:"Are you sure you want to cancel this upload?",dictRemoveFile:"Remove file",dictRemoveFileConfirmation:null,dictMaxFilesExceeded:"You can not upload any more files.",accept:function(a,b){return b()},init:function(){return g},forceFallback:!1,fallback:function(){var a,b,d,e,f,g;for(this.element.className=""+this.element.className+" dz-browser-not-supported",g=this.element.getElementsByTagName("div"),e=0,f=g.length;f>e;e++)a=g[e],/(^| )dz-message($| )/.test(a.className)&&(b=a,a.className="dz-message");return b||(b=c.createElement('
'),this.element.appendChild(b)),d=b.getElementsByTagName("span")[0],d&&(d.textContent=this.options.dictFallbackMessage),this.element.appendChild(this.getFallbackForm())},resize:function(a){var b,c,d;return b={srcX:0,srcY:0,srcWidth:a.width,srcHeight:a.height},c=a.width/a.height,b.optWidth=this.options.thumbnailWidth,b.optHeight=this.options.thumbnailHeight,null==b.optWidth&&null==b.optHeight?(b.optWidth=b.srcWidth,b.optHeight=b.srcHeight):null==b.optWidth?b.optWidth=c*b.optHeight:null==b.optHeight&&(b.optHeight=1/c*b.optWidth),d=b.optWidth/b.optHeight,a.heightd?(b.srcHeight=a.height,b.srcWidth=b.srcHeight*d):(b.srcWidth=a.width,b.srcHeight=b.srcWidth/d),b.srcX=(a.width-b.srcWidth)/2,b.srcY=(a.height-b.srcHeight)/2,b},drop:function(){return this.element.classList.remove("dz-drag-hover")},dragstart:g,dragend:function(){return this.element.classList.remove("dz-drag-hover")},dragenter:function(){return this.element.classList.add("dz-drag-hover")},dragover:function(){return this.element.classList.add("dz-drag-hover")},dragleave:function(){return this.element.classList.remove("dz-drag-hover")},paste:g,reset:function(){return this.element.classList.remove("dz-started")},addedfile:function(a){var b,d,e,f,g,h,i,j,k,l,m,n,o;if(this.element===this.previewsContainer&&this.element.classList.add("dz-started"),this.previewsContainer){for(a.previewElement=c.createElement(this.options.previewTemplate.trim()),a.previewTemplate=a.previewElement,this.previewsContainer.appendChild(a.previewElement),l=a.previewElement.querySelectorAll("[data-dz-name]"),f=0,i=l.length;i>f;f++)b=l[f],b.textContent=a.name;for(m=a.previewElement.querySelectorAll("[data-dz-size]"),g=0,j=m.length;j>g;g++)b=m[g],b.innerHTML=this.filesize(a.size);for(this.options.addRemoveLinks&&(a._removeLink=c.createElement(''+this.options.dictRemoveFile+""),a.previewElement.appendChild(a._removeLink)),d=function(b){return function(d){return d.preventDefault(),d.stopPropagation(),a.status===c.UPLOADING?c.confirm(b.options.dictCancelUploadConfirmation,function(){return b.removeFile(a)}):b.options.dictRemoveFileConfirmation?c.confirm(b.options.dictRemoveFileConfirmation,function(){return b.removeFile(a)}):b.removeFile(a)}}(this),n=a.previewElement.querySelectorAll("[data-dz-remove]"),o=[],h=0,k=n.length;k>h;h++)e=n[h],o.push(e.addEventListener("click",d));return o}},removedfile:function(a){var b;return a.previewElement&&null!=(b=a.previewElement)&&b.parentNode.removeChild(a.previewElement),this._updateMaxFilesReachedClass()},thumbnail:function(a,b){var c,d,e,f;if(a.previewElement){for(a.previewElement.classList.remove("dz-file-preview"),f=a.previewElement.querySelectorAll("[data-dz-thumbnail]"),d=0,e=f.length;e>d;d++)c=f[d],c.alt=a.name,c.src=b;return setTimeout(function(){return function(){return a.previewElement.classList.add("dz-image-preview")}}(this),1)}},error:function(a,b){var c,d,e,f,g;if(a.previewElement){for(a.previewElement.classList.add("dz-error"),"String"!=typeof b&&b.error&&(b=b.error),f=a.previewElement.querySelectorAll("[data-dz-errormessage]"),g=[],d=0,e=f.length;e>d;d++)c=f[d],g.push(c.textContent=b);return g}},errormultiple:g,processing:function(a){return a.previewElement&&(a.previewElement.classList.add("dz-processing"),a._removeLink)?a._removeLink.textContent=this.options.dictCancelUpload:void 0},processingmultiple:g,uploadprogress:function(a,b){var c,d,e,f,g;if(a.previewElement){for(f=a.previewElement.querySelectorAll("[data-dz-uploadprogress]"),g=[],d=0,e=f.length;e>d;d++)c=f[d],g.push("PROGRESS"===c.nodeName?c.value=b:c.style.width=""+b+"%");return g}},totaluploadprogress:g,sending:g,sendingmultiple:g,success:function(a){return a.previewElement?a.previewElement.classList.add("dz-success"):void 0},successmultiple:g,canceled:function(a){return this.emit("error",a,"Upload canceled.")},canceledmultiple:g,complete:function(a){return a._removeLink&&(a._removeLink.textContent=this.options.dictRemoveFile),a.previewElement?a.previewElement.classList.add("dz-complete"):void 0},completemultiple:g,maxfilesexceeded:g,maxfilesreached:g,queuecomplete:g,previewTemplate:'
\n
\n
\n
\n
\n
\n
\n
\n
\n \n Check\n \n \n \n \n \n
\n
\n \n Error\n \n \n \n \n \n \n \n
\n
'},d=function(){var a,b,c,d,e,f,g;for(d=arguments[0],c=2<=arguments.length?i.call(arguments,1):[],f=0,g=c.length;g>f;f++){b=c[f];for(a in b)e=b[a],d[a]=e}return d},c.prototype.getAcceptedFiles=function(){var a,b,c,d,e;for(d=this.files,e=[],b=0,c=d.length;c>b;b++)a=d[b],a.accepted&&e.push(a);return e},c.prototype.getRejectedFiles=function(){var a,b,c,d,e;for(d=this.files,e=[],b=0,c=d.length;c>b;b++)a=d[b],a.accepted||e.push(a);return e},c.prototype.getFilesWithStatus=function(a){var b,c,d,e,f;for(e=this.files,f=[],c=0,d=e.length;d>c;c++)b=e[c],b.status===a&&f.push(b);return f},c.prototype.getQueuedFiles=function(){return this.getFilesWithStatus(c.QUEUED)},c.prototype.getUploadingFiles=function(){return this.getFilesWithStatus(c.UPLOADING)},c.prototype.getActiveFiles=function(){var a,b,d,e,f;for(e=this.files,f=[],b=0,d=e.length;d>b;b++)a=e[b],(a.status===c.UPLOADING||a.status===c.QUEUED)&&f.push(a);return f},c.prototype.init=function(){var a,b,d,e,f,g,h;for("form"===this.element.tagName&&this.element.setAttribute("enctype","multipart/form-data"),this.element.classList.contains("dropzone")&&!this.element.querySelector(".dz-message")&&this.element.appendChild(c.createElement('
'+this.options.dictDefaultMessage+"
")),this.clickableElements.length&&(d=function(a){return function(){return a.hiddenFileInput&&document.body.removeChild(a.hiddenFileInput),a.hiddenFileInput=document.createElement("input"),a.hiddenFileInput.setAttribute("type","file"),(null==a.options.maxFiles||a.options.maxFiles>1)&&a.hiddenFileInput.setAttribute("multiple","multiple"),a.hiddenFileInput.className="dz-hidden-input",null!=a.options.acceptedFiles&&a.hiddenFileInput.setAttribute("accept",a.options.acceptedFiles),null!=a.options.capture&&a.hiddenFileInput.setAttribute("capture",a.options.capture),a.hiddenFileInput.style.visibility="hidden",a.hiddenFileInput.style.position="absolute",a.hiddenFileInput.style.top="0",a.hiddenFileInput.style.left="0",a.hiddenFileInput.style.height="0",a.hiddenFileInput.style.width="0",document.body.appendChild(a.hiddenFileInput),a.hiddenFileInput.addEventListener("change",function(){var b,c,e,f;if(c=a.hiddenFileInput.files,c.length)for(e=0,f=c.length;f>e;e++)b=c[e],a.addFile(b);return d()})}}(this))(),this.URL=null!=(g=window.URL)?g:window.webkitURL,h=this.events,e=0,f=h.length;f>e;e++)a=h[e],this.on(a,this.options[a]);return this.on("uploadprogress",function(a){return function(){return a.updateTotalUploadProgress()}}(this)),this.on("removedfile",function(a){return function(){return a.updateTotalUploadProgress()}}(this)),this.on("canceled",function(a){return function(b){return a.emit("complete",b)}}(this)),this.on("complete",function(a){return function(){return 0===a.getUploadingFiles().length&&0===a.getQueuedFiles().length?setTimeout(function(){return a.emit("queuecomplete")},0):void 0}}(this)),b=function(a){return a.stopPropagation(),a.preventDefault?a.preventDefault():a.returnValue=!1},this.listeners=[{element:this.element,events:{dragstart:function(a){return function(b){return a.emit("dragstart",b)}}(this),dragenter:function(a){return function(c){return b(c),a.emit("dragenter",c)}}(this),dragover:function(a){return function(c){var d;try{d=c.dataTransfer.effectAllowed}catch(e){}return c.dataTransfer.dropEffect="move"===d||"linkMove"===d?"move":"copy",b(c),a.emit("dragover",c)}}(this),dragleave:function(a){return function(b){return a.emit("dragleave",b)}}(this),drop:function(a){return function(c){return b(c),a.drop(c)}}(this),dragend:function(a){return function(b){return a.emit("dragend",b)}}(this)}}],this.clickableElements.forEach(function(a){return function(b){return a.listeners.push({element:b,events:{click:function(d){return b!==a.element||d.target===a.element||c.elementInside(d.target,a.element.querySelector(".dz-message"))?a.hiddenFileInput.click():void 0}}})}}(this)),this.enable(),this.options.init.call(this)},c.prototype.destroy=function(){var a;return this.disable(),this.removeAllFiles(!0),(null!=(a=this.hiddenFileInput)?a.parentNode:void 0)&&(this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput),this.hiddenFileInput=null),delete this.element.dropzone,c.instances.splice(c.instances.indexOf(this),1)},c.prototype.updateTotalUploadProgress=function(){var a,b,c,d,e,f,g,h;if(d=0,c=0,a=this.getActiveFiles(),a.length){for(h=this.getActiveFiles(),f=0,g=h.length;g>f;f++)b=h[f],d+=b.upload.bytesSent,c+=b.upload.total;e=100*d/c}else e=100;return this.emit("totaluploadprogress",e,c,d)},c.prototype._getParamName=function(a){return"function"==typeof this.options.paramName?this.options.paramName(a):""+this.options.paramName+(this.options.uploadMultiple?"["+a+"]":"")},c.prototype.getFallbackForm=function(){var a,b,d,e;return(a=this.getExistingFallback())?a:(d='
',this.options.dictFallbackText&&(d+="

"+this.options.dictFallbackText+"

"),d+='
',b=c.createElement(d),"FORM"!==this.element.tagName?(e=c.createElement('
'),e.appendChild(b)):(this.element.setAttribute("enctype","multipart/form-data"),this.element.setAttribute("method",this.options.method)),null!=e?e:b)},c.prototype.getExistingFallback=function(){var a,b,c,d,e,f;for(b=function(a){var b,c,d;for(c=0,d=a.length;d>c;c++)if(b=a[c],/(^| )fallback($| )/.test(b.className))return b},f=["div","form"],d=0,e=f.length;e>d;d++)if(c=f[d],a=b(this.element.getElementsByTagName(c)))return a},c.prototype.setupEventListeners=function(){var a,b,c,d,e,f,g;for(f=this.listeners,g=[],d=0,e=f.length;e>d;d++)a=f[d],g.push(function(){var d,e;d=a.events,e=[];for(b in d)c=d[b],e.push(a.element.addEventListener(b,c,!1));return e}());return g},c.prototype.removeEventListeners=function(){var a,b,c,d,e,f,g;for(f=this.listeners,g=[],d=0,e=f.length;e>d;d++)a=f[d],g.push(function(){var d,e;d=a.events,e=[];for(b in d)c=d[b],e.push(a.element.removeEventListener(b,c,!1));return e}());return g},c.prototype.disable=function(){var a,b,c,d,e;for(this.clickableElements.forEach(function(a){return a.classList.remove("dz-clickable")}),this.removeEventListeners(),d=this.files,e=[],b=0,c=d.length;c>b;b++)a=d[b],e.push(this.cancelUpload(a));return e},c.prototype.enable=function(){return this.clickableElements.forEach(function(a){return a.classList.add("dz-clickable")}),this.setupEventListeners()},c.prototype.filesize=function(a){var b,c,d,e,f,g,h,i;for(g=["TB","GB","MB","KB","b"],d=e=null,c=h=0,i=g.length;i>h;c=++h)if(f=g[c],b=Math.pow(this.options.filesizeBase,4-c)/10,a>=b){d=a/Math.pow(this.options.filesizeBase,4-c),e=f;break}return d=Math.round(10*d)/10,""+d+" "+e},c.prototype._updateMaxFilesReachedClass=function(){return null!=this.options.maxFiles&&this.getAcceptedFiles().length>=this.options.maxFiles?(this.getAcceptedFiles().length===this.options.maxFiles&&this.emit("maxfilesreached",this.files),this.element.classList.add("dz-max-files-reached")):this.element.classList.remove("dz-max-files-reached")},c.prototype.drop=function(a){var b,c;a.dataTransfer&&(this.emit("drop",a),b=a.dataTransfer.files,b.length&&(c=a.dataTransfer.items,c&&c.length&&null!=c[0].webkitGetAsEntry?this._addFilesFromItems(c):this.handleFiles(b)))},c.prototype.paste=function(a){var b,c;if(null!=(null!=a&&null!=(c=a.clipboardData)?c.items:void 0))return this.emit("paste",a),b=a.clipboardData.items,b.length?this._addFilesFromItems(b):void 0},c.prototype.handleFiles=function(a){var b,c,d,e;for(e=[],c=0,d=a.length;d>c;c++)b=a[c],e.push(this.addFile(b));return e},c.prototype._addFilesFromItems=function(a){var b,c,d,e,f;for(f=[],d=0,e=a.length;e>d;d++)c=a[d],f.push(null!=c.webkitGetAsEntry&&(b=c.webkitGetAsEntry())?b.isFile?this.addFile(c.getAsFile()):b.isDirectory?this._addFilesFromDirectory(b,b.name):void 0:null!=c.getAsFile?null==c.kind||"file"===c.kind?this.addFile(c.getAsFile()):void 0:void 0);return f},c.prototype._addFilesFromDirectory=function(a,b){var c,d;return c=a.createReader(),d=function(a){return function(c){var d,e,f;for(e=0,f=c.length;f>e;e++)d=c[e],d.isFile?d.file(function(c){return a.options.ignoreHiddenFiles&&"."===c.name.substring(0,1)?void 0:(c.fullPath=""+b+"/"+c.name,a.addFile(c))}):d.isDirectory&&a._addFilesFromDirectory(d,""+b+"/"+d.name)}}(this),c.readEntries(d,function(a){return"undefined"!=typeof console&&null!==console&&"function"==typeof console.log?console.log(a):void 0})},c.prototype.accept=function(a,b){return a.size>1024*this.options.maxFilesize*1024?b(this.options.dictFileTooBig.replace("{{filesize}}",Math.round(a.size/1024/10.24)/100).replace("{{maxFilesize}}",this.options.maxFilesize)):c.isValidFile(a,this.options.acceptedFiles)?null!=this.options.maxFiles&&this.getAcceptedFiles().length>=this.options.maxFiles?(b(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}",this.options.maxFiles)),this.emit("maxfilesexceeded",a)):this.options.accept.call(this,a,b):b(this.options.dictInvalidFileType)},c.prototype.addFile=function(a){return a.upload={progress:0,total:a.size,bytesSent:0},this.files.push(a),a.status=c.ADDED,this.emit("addedfile",a),this._enqueueThumbnail(a),this.accept(a,function(b){return function(c){return c?(a.accepted=!1,b._errorProcessing([a],c)):(a.accepted=!0,b.options.autoQueue&&b.enqueueFile(a)),b._updateMaxFilesReachedClass()}}(this))},c.prototype.enqueueFiles=function(a){var b,c,d;for(c=0,d=a.length;d>c;c++)b=a[c],this.enqueueFile(b);return null},c.prototype.enqueueFile=function(a){if(a.status!==c.ADDED||a.accepted!==!0)throw new Error("This file can't be queued because it has already been processed or was rejected.");return a.status=c.QUEUED,this.options.autoProcessQueue?setTimeout(function(a){return function(){return a.processQueue()}}(this),0):void 0},c.prototype._thumbnailQueue=[],c.prototype._processingThumbnail=!1,c.prototype._enqueueThumbnail=function(a){return this.options.createImageThumbnails&&a.type.match(/image.*/)&&a.size<=1024*this.options.maxThumbnailFilesize*1024?(this._thumbnailQueue.push(a),setTimeout(function(a){return function(){return a._processThumbnailQueue()}}(this),0)):void 0},c.prototype._processThumbnailQueue=function(){return this._processingThumbnail||0===this._thumbnailQueue.length?void 0:(this._processingThumbnail=!0,this.createThumbnail(this._thumbnailQueue.shift(),function(a){return function(){return a._processingThumbnail=!1,a._processThumbnailQueue()}}(this)))},c.prototype.removeFile=function(a){return a.status===c.UPLOADING&&this.cancelUpload(a),this.files=h(this.files,a),this.emit("removedfile",a),0===this.files.length?this.emit("reset"):void 0},c.prototype.removeAllFiles=function(a){var b,d,e,f;for(null==a&&(a=!1),f=this.files.slice(),d=0,e=f.length;e>d;d++)b=f[d],(b.status!==c.UPLOADING||a)&&this.removeFile(b);return null},c.prototype.createThumbnail=function(a,b){var c;return c=new FileReader,c.onload=function(d){return function(){var e;return"image/svg+xml"===a.type?(d.emit("thumbnail",a,c.result),void(null!=b&&b())):(e=document.createElement("img"),e.onload=function(){var c,g,h,i,j,k,l,m;return a.width=e.width,a.height=e.height,h=d.options.resize.call(d,a),null==h.trgWidth&&(h.trgWidth=h.optWidth),null==h.trgHeight&&(h.trgHeight=h.optHeight),c=document.createElement("canvas"),g=c.getContext("2d"),c.width=h.trgWidth,c.height=h.trgHeight,f(g,e,null!=(j=h.srcX)?j:0,null!=(k=h.srcY)?k:0,h.srcWidth,h.srcHeight,null!=(l=h.trgX)?l:0,null!=(m=h.trgY)?m:0,h.trgWidth,h.trgHeight),i=c.toDataURL("image/png"),d.emit("thumbnail",a,i),null!=b?b():void 0},e.onerror=b,e.src=c.result)}}(this),c.readAsDataURL(a)},c.prototype.processQueue=function(){var a,b,c,d;if(b=this.options.parallelUploads,c=this.getUploadingFiles().length,a=c,!(c>=b)&&(d=this.getQueuedFiles(),d.length>0)){if(this.options.uploadMultiple)return this.processFiles(d.slice(0,b-c));for(;b>a;){if(!d.length)return;this.processFile(d.shift()),a++}}},c.prototype.processFile=function(a){return this.processFiles([a])},c.prototype.processFiles=function(a){var b,d,e;for(d=0,e=a.length;e>d;d++)b=a[d],b.processing=!0,b.status=c.UPLOADING,this.emit("processing",b);return this.options.uploadMultiple&&this.emit("processingmultiple",a),this.uploadFiles(a)},c.prototype._getFilesWithXhr=function(a){var b,c;return c=function(){var c,d,e,f;for(e=this.files,f=[],c=0,d=e.length;d>c;c++)b=e[c],b.xhr===a&&f.push(b);return f}.call(this)},c.prototype.cancelUpload=function(a){var b,d,e,f,g,h,i;if(a.status===c.UPLOADING){for(d=this._getFilesWithXhr(a.xhr),e=0,g=d.length;g>e;e++)b=d[e],b.status=c.CANCELED;for(a.xhr.abort(),f=0,h=d.length;h>f;f++)b=d[f],this.emit("canceled",b);this.options.uploadMultiple&&this.emit("canceledmultiple",d)}else((i=a.status)===c.ADDED||i===c.QUEUED)&&(a.status=c.CANCELED,this.emit("canceled",a),this.options.uploadMultiple&&this.emit("canceledmultiple",[a]));return this.options.autoProcessQueue?this.processQueue():void 0},e=function(){var a,b;return b=arguments[0],a=2<=arguments.length?i.call(arguments,1):[],"function"==typeof b?b.apply(this,a):b},c.prototype.uploadFile=function(a){return this.uploadFiles([a])},c.prototype.uploadFiles=function(a){var b,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L;for(w=new XMLHttpRequest,x=0,B=a.length;B>x;x++)b=a[x],b.xhr=w;p=e(this.options.method,a),u=e(this.options.url,a),w.open(p,u,!0),w.withCredentials=!!this.options.withCredentials,s=null,g=function(c){return function(){var d,e,f;for(f=[],d=0,e=a.length;e>d;d++)b=a[d],f.push(c._errorProcessing(a,s||c.options.dictResponseError.replace("{{statusCode}}",w.status),w));return f}}(this),t=function(c){return function(d){var e,f,g,h,i,j,k,l,m;if(null!=d)for(f=100*d.loaded/d.total,g=0,j=a.length;j>g;g++)b=a[g],b.upload={progress:f,total:d.total,bytesSent:d.loaded};else{for(e=!0,f=100,h=0,k=a.length;k>h;h++)b=a[h],(100!==b.upload.progress||b.upload.bytesSent!==b.upload.total)&&(e=!1),b.upload.progress=f,b.upload.bytesSent=b.upload.total;if(e)return}for(m=[],i=0,l=a.length;l>i;i++)b=a[i],m.push(c.emit("uploadprogress",b,f,b.upload.bytesSent));return m}}(this),w.onload=function(b){return function(d){var e;if(a[0].status!==c.CANCELED&&4===w.readyState){if(s=w.responseText,w.getResponseHeader("content-type")&&~w.getResponseHeader("content-type").indexOf("application/json"))try{s=JSON.parse(s)}catch(f){d=f,s="Invalid JSON response from server."}return t(),200<=(e=w.status)&&300>e?b._finished(a,s,d):g()}}}(this),w.onerror=function(){return function(){return a[0].status!==c.CANCELED?g():void 0}}(this),r=null!=(G=w.upload)?G:w,r.onprogress=t,j={Accept:"application/json","Cache-Control":"no-cache","X-Requested-With":"XMLHttpRequest"},this.options.headers&&d(j,this.options.headers);for(h in j)i=j[h],w.setRequestHeader(h,i);if(f=new FormData,this.options.params){H=this.options.params;for(o in H)v=H[o],f.append(o,v)}for(y=0,C=a.length;C>y;y++)b=a[y],this.emit("sending",b,w,f);if(this.options.uploadMultiple&&this.emit("sendingmultiple",a,w,f),"FORM"===this.element.tagName)for(I=this.element.querySelectorAll("input, textarea, select, button"),z=0,D=I.length;D>z;z++)if(l=I[z],m=l.getAttribute("name"),n=l.getAttribute("type"),"SELECT"===l.tagName&&l.hasAttribute("multiple"))for(J=l.options,A=0,E=J.length;E>A;A++)q=J[A],q.selected&&f.append(m,q.value);else(!n||"checkbox"!==(K=n.toLowerCase())&&"radio"!==K||l.checked)&&f.append(m,l.value);for(k=F=0,L=a.length-1;L>=0?L>=F:F>=L;k=L>=0?++F:--F)f.append(this._getParamName(k),a[k],a[k].name);return w.send(f)},c.prototype._finished=function(a,b,d){var e,f,g;for(f=0,g=a.length;g>f;f++)e=a[f],e.status=c.SUCCESS,this.emit("success",e,b,d),this.emit("complete",e);return this.options.uploadMultiple&&(this.emit("successmultiple",a,b,d),this.emit("completemultiple",a)),this.options.autoProcessQueue?this.processQueue():void 0},c.prototype._errorProcessing=function(a,b,d){var e,f,g;for(f=0,g=a.length;g>f;f++)e=a[f],e.status=c.ERROR,this.emit("error",e,b,d),this.emit("complete",e);return this.options.uploadMultiple&&(this.emit("errormultiple",a,b,d),this.emit("completemultiple",a)),this.options.autoProcessQueue?this.processQueue():void 0},c}(b),a.version="4.0.1",a.options={},a.optionsForElement=function(b){return b.getAttribute("id")?a.options[c(b.getAttribute("id"))]:void 0},a.instances=[],a.forElement=function(a){if("string"==typeof a&&(a=document.querySelector(a)),null==(null!=a?a.dropzone:void 0))throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone.");return a.dropzone},a.autoDiscover=!0,a.discover=function(){var b,c,d,e,f,g;for(document.querySelectorAll?d=document.querySelectorAll(".dropzone"):(d=[],b=function(a){var b,c,e,f;for(f=[],c=0,e=a.length;e>c;c++)b=a[c],f.push(/(^| )dropzone($| )/.test(b.className)?d.push(b):void 0);return f},b(document.getElementsByTagName("div")),b(document.getElementsByTagName("form"))),g=[],e=0,f=d.length;f>e;e++)c=d[e],g.push(a.optionsForElement(c)!==!1?new a(c):void 0);return g},a.blacklistedBrowsers=[/opera.*Macintosh.*version\/12/i],a.isBrowserSupported=function(){var b,c,d,e,f;if(b=!0,window.File&&window.FileReader&&window.FileList&&window.Blob&&window.FormData&&document.querySelector)if("classList"in document.createElement("a"))for(f=a.blacklistedBrowsers,d=0,e=f.length;e>d;d++)c=f[d],c.test(navigator.userAgent)&&(b=!1);else b=!1;else b=!1;return b},h=function(a,b){var c,d,e,f;for(f=[],d=0,e=a.length;e>d;d++)c=a[d],c!==b&&f.push(c);return f},c=function(a){return a.replace(/[\-_](\w)/g,function(a){return a.charAt(1).toUpperCase()})},a.createElement=function(a){var b;return b=document.createElement("div"),b.innerHTML=a,b.childNodes[0]},a.elementInside=function(a,b){if(a===b)return!0;for(;a=a.parentNode;)if(a===b)return!0;return!1},a.getElement=function(a,b){var c;if("string"==typeof a?c=document.querySelector(a):null!=a.nodeType&&(c=a),null==c)throw new Error("Invalid `"+b+"` option provided. Please provide a CSS selector or a plain HTML element.");return c},a.getElements=function(a,b){var c,d,e,f,g,h,i,j;if(a instanceof Array){e=[];try{for(f=0,h=a.length;h>f;f++)d=a[f],e.push(this.getElement(d,b))}catch(k){c=k,e=null}}else if("string"==typeof a)for(e=[],j=document.querySelectorAll(a),g=0,i=j.length;i>g;g++)d=j[g],e.push(d);else null!=a.nodeType&&(e=[a]);if(null==e||!e.length)throw new Error("Invalid `"+b+"` option provided. Please provide a CSS selector, a plain HTML element or a list of those.");return e},a.confirm=function(a,b,c){return window.confirm(a)?b():null!=c?c():void 0},a.isValidFile=function(a,b){var c,d,e,f,g;if(!b)return!0;for(b=b.split(","),d=a.type,c=d.replace(/\/.*$/,""),f=0,g=b.length;g>f;f++)if(e=b[f],e=e.trim(),"."===e.charAt(0)){if(-1!==a.name.toLowerCase().indexOf(e.toLowerCase(),a.name.length-e.length))return!0}else if(/\/\*$/.test(e)){if(c===e.replace(/\/.*$/,""))return!0}else if(d===e)return!0;return!1},"undefined"!=typeof jQuery&&null!==jQuery&&(jQuery.fn.dropzone=function(b){return this.each(function(){return new a(this,b)})}),"undefined"!=typeof module&&null!==module?module.exports=a:window.Dropzone=a,a.ADDED="added",a.QUEUED="queued",a.ACCEPTED=a.QUEUED,a.UPLOADING="uploading",a.PROCESSING=a.UPLOADING,a.CANCELED="canceled",a.ERROR="error",a.SUCCESS="success",e=function(a){var b,c,d,e,f,g,h,i,j,k;for(h=a.naturalWidth,g=a.naturalHeight,c=document.createElement("canvas"),c.width=1,c.height=g,d=c.getContext("2d"),d.drawImage(a,0,0),e=d.getImageData(0,0,1,g).data,k=0,f=g,i=g;i>k;)b=e[4*(i-1)+3],0===b?f=i:k=i,i=f+k>>1;return j=i/g,0===j?1:j},f=function(a,b,c,d,f,g,h,i,j,k){var l;return l=e(b),a.drawImage(b,c,d,f,g,h,i,j,k/l)},d=function(a,b){var c,d,e,f,g,h,i,j,k;if(e=!1,k=!0,d=a.document,j=d.documentElement,c=d.addEventListener?"addEventListener":"attachEvent",i=d.addEventListener?"removeEventListener":"detachEvent",h=d.addEventListener?"":"on",f=function(c){return"readystatechange"!==c.type||"complete"===d.readyState?(("load"===c.type?a:d)[i](h+c.type,f,!1),!e&&(e=!0)?b.call(a,c.type||c):void 0):void 0 +},g=function(){var a;try{j.doScroll("left")}catch(b){return a=b,void setTimeout(g,50)}return f("poll")},"complete"!==d.readyState){if(d.createEventObject&&j.doScroll){try{k=!a.frameElement}catch(l){}k&&g()}return d[c](h+"DOMContentLoaded",f,!1),d[c](h+"readystatechange",f,!1),a[c](h+"load",f,!1)}},a._autoDiscoverFunction=function(){return a.autoDiscover?a.discover():void 0},d(window,a._autoDiscoverFunction)}).call(this); \ No newline at end of file