diff --git a/airtime_mvc/application/common/FileDataHelper.php b/airtime_mvc/application/common/FileDataHelper.php index 568b25d4d..6ad391dbc 100644 --- a/airtime_mvc/application/common/FileDataHelper.php +++ b/airtime_mvc/application/common/FileDataHelper.php @@ -14,6 +14,7 @@ class FileDataHelper { "audio/aac" => "aac", "audio/aacp" => "aac", "audio/mp4" => "m4a", + "video/mp4" => "mp4", "audio/x-flac" => "flac", "audio/wav" => "wav", "audio/x-wav" => "wav", diff --git a/airtime_mvc/application/forms/SoundCloudPreferences.php b/airtime_mvc/application/forms/SoundCloudPreferences.php index 987244ced..d6478fbf0 100644 --- a/airtime_mvc/application/forms/SoundCloudPreferences.php +++ b/airtime_mvc/application/forms/SoundCloudPreferences.php @@ -40,6 +40,7 @@ class Application_Form_SoundcloudPreferences extends Zend_Form_SubForm $this->addElement('image', 'SoundCloudConnect', array( 'src' => 'http://connect.soundcloud.com/2/btn-connect-sc-l.png', + 'target' => '_blank', 'decorators' => array( 'ViewHelper' ) @@ -47,6 +48,7 @@ class Application_Form_SoundcloudPreferences extends Zend_Form_SubForm $this->addElement('image', 'SoundCloudDisconnect', array( 'src' => 'http://connect.soundcloud.com/2/btn-disconnect-l.png', + 'target' => '_blank', 'decorators' => array( 'ViewHelper' ) diff --git a/airtime_mvc/application/layouts/scripts/layout.phtml b/airtime_mvc/application/layouts/scripts/layout.phtml index 810f56462..d3505d349 100644 --- a/airtime_mvc/application/layouts/scripts/layout.phtml +++ b/airtime_mvc/application/layouts/scripts/layout.phtml @@ -80,6 +80,12 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= +
+ + + + +

-
- - - - -
+ \ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/library/library.js b/airtime_mvc/public/js/airtime/library/library.js index 3c7cf7151..382a07c81 100644 --- a/airtime_mvc/public/js/airtime/library/library.js +++ b/airtime_mvc/public/js/airtime/library/library.js @@ -1255,7 +1255,9 @@ var AIRTIME = (function(AIRTIME) { * @param table the table to show */ mod.setCurrentTable = function (table) { - if (oTable) oTable.fnClearTable(); + if (oTable && oTable === $datatables[mod.DataTableTypeEnum.PODCAST_EPISODES]) { + oTable.fnClearTable(); + } var dt = $datatables[table], wrapper = $(dt).closest(".dataTables_wrapper"); $("#library_content").find(".dataTables_wrapper").hide(); @@ -1718,8 +1720,9 @@ var validationTypes = { $(document).ready(function() { - - AIRTIME.library.initPodcastDatatable(); + if (window.location.href.indexOf("showbuilder") > -1) { + AIRTIME.library.initPodcastDatatable(); + } $("#advanced-options").on("click", function() { resizeAdvancedSearch(); diff --git a/airtime_mvc/public/js/airtime/library/podcast.js b/airtime_mvc/public/js/airtime/library/podcast.js index cecdb7e91..0f7edf00e 100644 --- a/airtime_mvc/public/js/airtime/library/podcast.js +++ b/airtime_mvc/public/js/airtime/library/podcast.js @@ -146,10 +146,21 @@ var AIRTIME = (function (AIRTIME) { * Sets up the internal datatable. */ PodcastController.prototype.initialize = function() { + var self = this; // TODO: this solves a race condition, but we should look for the root cause AIRTIME.tabs.onResize(); - this.$scope.tab.setName(this.$scope.podcast.title); - this._initTable(); + self.$scope.tab.setName(self.$scope.podcast.title); + self._initTable(); + // Add an onclose hook to the tab to remove the table object and the + // import listener so we don't cause memory leaks. + if (self.episodeTable) { + self.$scope.tab.assignOnCloseHandler(function () { + self.episodeTable.destroy(); + self.episodeTable = null; + self.$scope.tab = null; + self.$scope.$destroy(); + }); + } }; /** @@ -444,6 +455,7 @@ var AIRTIME = (function (AIRTIME) { self.importListener = setInterval(function () { var podcastId = self.config.podcastId, pendingRows = []; if (!podcastId) return false; + console.log(self); var dt = self.getDatatable(), data = dt.fnGetData(); // Iterate over the table data to check for any rows pending import $.each(data, function () { @@ -475,6 +487,13 @@ var AIRTIME = (function (AIRTIME) { } }, 10000); // Run every 10 seconds }; + + /** + * Explicit destructor + */ + PodcastEpisodeTable.prototype.destroy = function () { + clearInterval(this.importListener); + } } /** @@ -552,9 +571,9 @@ var AIRTIME = (function (AIRTIME) { */ mod.editSelectedEpisodes = function (episodes) { $.each(episodes, function () { - if (!Object.keys(this.file).length > 0) return false; - var uid = AIRTIME.library.MediaTypeStringEnum.FILE + "_" + this.file.id; - $.get(baseUrl + "library/edit-file-md/id/" + this.file.id, {format: "json"}, function (json) { + if (this.file && !Object.keys(this.file).length > 0) return false; + var fileId = this.file_id || this.file.id, uid = AIRTIME.library.MediaTypeStringEnum.FILE + "_" + fileId; + $.get(baseUrl + "library/edit-file-md/id/" + fileId, {format: "json"}, function (json) { AIRTIME.playlist.fileMdEdit(json, uid); }); }); @@ -568,7 +587,7 @@ var AIRTIME = (function (AIRTIME) { */ mod.importSelectedEpisodes = function (episodes, dt) { $.each(episodes, function () { - if (Object.keys(this.file).length > 0) return false; + if (this.file && Object.keys(this.file).length > 0) return false; var podcastId = this.podcast_id; $.post(endpoint + podcastId + '/episodes', JSON.stringify({ csrf_token: $("#csrf").val(), diff --git a/airtime_mvc/public/js/airtime/library/publish.js b/airtime_mvc/public/js/airtime/library/publish.js index a1ee4de7b..5eb362bc7 100644 --- a/airtime_mvc/public/js/airtime/library/publish.js +++ b/airtime_mvc/public/js/airtime/library/publish.js @@ -59,7 +59,7 @@ var AIRTIME = (function (AIRTIME) { } }); - if (Object.keys(data).length > 0) { + if (data && Object.keys(data).length > 0) { $http.put(endpoint + mediaId + '/publish', {csrf_token: jQuery("#csrf").val(), sources: data}) .success(function () { init(); diff --git a/airtime_mvc/public/js/airtime/schedule/schedule.js b/airtime_mvc/public/js/airtime/schedule/schedule.js index 110054eeb..cb05b889e 100644 --- a/airtime_mvc/public/js/airtime/schedule/schedule.js +++ b/airtime_mvc/public/js/airtime/schedule/schedule.js @@ -216,7 +216,7 @@ function buildScheduleDialog (json, instance_id) { buttons: [ { text: $.i18n._("Ok"), - "class": "btn", + class: "btn", click: function() { $(this).dialog("close"); //getUsabilityHint(); diff --git a/airtime_mvc/public/js/airtime/showbuilder/tabs.js b/airtime_mvc/public/js/airtime/showbuilder/tabs.js index 0268c390e..93ad41911 100644 --- a/airtime_mvc/public/js/airtime/showbuilder/tabs.js +++ b/airtime_mvc/public/js/airtime/showbuilder/tabs.js @@ -136,6 +136,13 @@ var AIRTIME = (function(AIRTIME){ }); }; + /** + * Internal destructor. Can be assigned via assignOnCloseHandler + * + * @private + */ + Tab.prototype._destroy = function () {} + /** * Assign the given function f as the click handler for the tab * @@ -164,6 +171,15 @@ var AIRTIME = (function(AIRTIME){ this.tab.find(".lib_pl_close").unbind("click").click(f); }; + /** + * Assign an implicit destructor + * + * @param {function} fn function to run when this Tab is destroyed + */ + Tab.prototype.assignOnCloseHandler = function (fn) { + this._destroy = fn; + }; + /** * Open this tab in the right-hand pane and set it as the currently active tab */ @@ -205,6 +221,8 @@ var AIRTIME = (function(AIRTIME){ } else { mod.onResize(); } + + self._destroy(); }; /**