diff --git a/airtime_mvc/application/common/widgets/Table.php b/airtime_mvc/application/common/widgets/Table.php
new file mode 100644
index 000000000..0692debff
--- /dev/null
+++ b/airtime_mvc/application/common/widgets/Table.php
@@ -0,0 +1,30 @@
+appendFile($baseUrl . $deps[$i] .'?'. $airtimeVersion, 'text/javascript');
+ }
+ }
+}
\ No newline at end of file
diff --git a/airtime_mvc/application/controllers/DashboardController.php b/airtime_mvc/application/controllers/DashboardController.php
index 660a6b61c..dbf273f03 100644
--- a/airtime_mvc/application/controllers/DashboardController.php
+++ b/airtime_mvc/application/controllers/DashboardController.php
@@ -1,5 +1,7 @@
view->airtime_version = Application_Model_Preference::GetAirtimeVersion();
}
+ public function tableTestAction()
+ {
+ Zend_Layout::getMvcInstance()->assign('parent_page', 'Help');
+
+ $CC_CONFIG = Config::getConfig();
+
+ $baseUrl = Application_Common_OsPath::getBaseDir();
+
+ $headScript = $this->view->headScript();
+ AirtimeTableView::injectTableJavaScriptDependencies($headScript, $baseUrl, $CC_CONFIG['airtime_version']);
+ $this->view->headScript()->appendFile($baseUrl.'js/airtime/widgets/table-example.js?'.$CC_CONFIG['airtime_version']);
+
+ }
}
diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php
index b43bac3c0..d276e829b 100644
--- a/airtime_mvc/application/modules/rest/controllers/MediaController.php
+++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php
@@ -21,13 +21,20 @@ class Rest_MediaController extends Zend_Rest_Controller
$offset = $this->_getParam('offset', 0);
$limit = $this->_getParam('limit', $totalFileCount);
+ //Sorting parameters
+ $sortColumn = $this->_getParam('sort', CcFilesPeer::ID);
+ $sortDir = $this->_getParam('sort_dir', Criteria::ASC);
+
$query = CcFilesQuery::create()
->filterByDbHidden(false)
->filterByDbFileExists(true)
->filterByDbImportStatus(0)
->setLimit($limit)
->setOffset($offset)
- ->orderByDbId();
+ ->orderBy($sortColumn, $sortDir);
+ //->orderByDbId();
+
+
$queryCount = $query->count();
$queryResult = $query->find();
@@ -39,7 +46,7 @@ class Rest_MediaController extends Zend_Rest_Controller
$this->getResponse()
->setHttpResponseCode(200)
- ->setHeader('X-TOTAL-COUNT', $queryCount)
+ ->setHeader('X-TOTAL-COUNT', $totalFileCount)
->appendBody(json_encode($files_array));
/** TODO: Use this simpler code instead after we upgrade to Propel 1.7 (Airtime 2.6.x branch):
diff --git a/airtime_mvc/application/views/scripts/dashboard/table-test.phtml b/airtime_mvc/application/views/scripts/dashboard/table-test.phtml
new file mode 100644
index 000000000..63c849b6d
--- /dev/null
+++ b/airtime_mvc/application/views/scripts/dashboard/table-test.phtml
@@ -0,0 +1,7 @@
+
diff --git a/airtime_mvc/public/js/airtime/library/library.js b/airtime_mvc/public/js/airtime/library/library.js
index 760998b00..cb03e112b 100644
--- a/airtime_mvc/public/js/airtime/library/library.js
+++ b/airtime_mvc/public/js/airtime/library/library.js
@@ -1256,25 +1256,6 @@ var AIRTIME = (function(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
*/
diff --git a/airtime_mvc/public/js/airtime/widgets/table-example.js b/airtime_mvc/public/js/airtime/widgets/table-example.js
new file mode 100644
index 000000000..fa5a21835
--- /dev/null
+++ b/airtime_mvc/public/js/airtime/widgets/table-example.js
@@ -0,0 +1,24 @@
+/**
+ * Created by asantoni on 11/09/15.
+ */
+
+
+$(document).ready(function() {
+ var aoColumns = [
+ /* Title */ { "sTitle" : $.i18n._("Title") , "mDataProp" : "track_title" , "sClass" : "library_title" , "sWidth" : "170px" },
+ /* Creator */ { "sTitle" : $.i18n._("Creator") , "mDataProp" : "artist_name" , "sClass" : "library_creator" , "sWidth" : "160px" },
+ /* Upload Time */ { "sTitle" : $.i18n._("Uploaded") , "mDataProp" : "utime" , "bVisible" : false , "sClass" : "library_upload_time" , "sWidth" : "155px" },
+ /* 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" },
+ ];
+ var ajaxSourceURL = baseUrl+"rest/media";
+
+ //Set up the div with id "example-table" as a datatable.
+ var table = AIRTIME.widgets.table.init(
+ $('#example-table'), //DOM node to create the table inside.
+ true, //Enable item selection
+ { //Datatables overrides.
+ 'aoColumns' : aoColumns,
+ 'sAjaxSource' : ajaxSourceURL
+ });
+});
diff --git a/airtime_mvc/public/js/airtime/widgets/table.js b/airtime_mvc/public/js/airtime/widgets/table.js
new file mode 100644
index 000000000..ccdf8fffb
--- /dev/null
+++ b/airtime_mvc/public/js/airtime/widgets/table.js
@@ -0,0 +1,326 @@
+/**
+ * Created by asantoni on 11/09/15.
+ */
+
+var AIRTIME = (function(AIRTIME) {
+
+ //Module initialization
+ if (AIRTIME.widgets === undefined) {
+ AIRTIME.widgets = {};
+ }
+ if (AIRTIME.widgets.table === undefined) {
+ AIRTIME.widgets.table = {};
+ }
+
+ var self;
+ var self = AIRTIME.widgets.table;
+
+ //Constants
+ self.SELECTION_MODE = {
+ SINGLE : 0,
+ MULTI_SHIFT : 1,
+ MULTI_CTRL : 2
+ }
+
+ self.HUGE_INT = Math.pow(2, 53) - 1;
+
+ //Member variables
+ self._datatable = null;
+ self._selectedRows = []; //An array containing the underlying objects for each selected row. (Easy to use!)
+ //self._selectedRowVisualIdxMap = []; //A map of the visual index of a selected rows onto the actual row data.
+ self._selectedRowVisualIdxMin = self.HUGE_INT;
+ self._selectedRowVisualIdxMax = -1;
+ self._$wrapperDOMNode = null;
+
+
+ //Member functions
+ self.init = function(wrapperDOMNode, bItemSelection, dataTablesOptions) {
+ self._$wrapperDOMNode = $(wrapperDOMNode);
+
+ //TODO: If selection is enabled, add in the checkbox column.
+ if (bItemSelection) {
+ dataTablesOptions["aoColumns"].unshift(
+ /* Checkbox */ { "sTitle" : "", "mData" : self._datatablesCheckboxDataDelegate, "bSortable" : false , "bSearchable" : false , "sWidth" : "16px" , "sClass" : "library_checkbox" }
+ );
+
+ dataTablesOptions["fnRowCallback"] = self._rowCreatedCallback;
+ }
+
+ var options = {
+ "aoColumns": [
+ /* Title */ { "sTitle" : $.i18n._("Make sure to override me") , "mDataProp" : "track_title" , "sClass" : "library_title" , "sWidth" : "170px" },
+ ],
+ "bProcessing": true,
+ "bServerSide": true,
+ "sAjaxSource": baseUrl+"rest/media", //Override me
+ "sAjaxDataProp": "aaData",
+ "bScrollCollapse": false,
+ "sPaginationType": "full_numbers",
+ "bJQueryUI": true,
+ "bAutoWidth": false,
+ "aaSorting": [],
+ "oLanguage" : getDatatablesStrings({
+ "sEmptyTable": $.i18n._(""),
+ "sZeroRecords": $.i18n._("No matching results found.")
+ }),
+ "oColVis": {
+ "sAlign": "right",
+ "buttonText": $.i18n._("Columns"),
+ "iOverlayFade": 0
+ },
+ // z = ColResize, R = ColReorder, C = ColVis
+ "sDom": 'Rf<"dt-process-rel"r><"H"<"library_toolbar"C>><"dataTables_scrolling"t<"#library_empty"<"#library_empty_image"><"#library_empty_text">>><"F"lip>>',
+
+ "fnServerData": self._fetchData,
+ "fnDrawCallback" : self._tableDrawCallback
+ };
+
+ //Override any options with those passed in as arguments to this constructor.
+ for (var key in dataTablesOptions)
+ {
+ options[key] = dataTablesOptions[key];
+ }
+
+ self._datatable = self._$wrapperDOMNode.dataTable(options);
+
+ };
+
+ self._handleAjaxError = function(r) {
+ // If the request was denied due to permissioning
+ if (r.status === 403) {
+ // Hide the processing div
+ /*
+ $("#library_display_wrapper").find(".dt-process-rel").hide();
+ $.getJSON( "ajax/library_placeholders.json", function( data ) {
+ $('#library_empty_text').text($.i18n._(data.unauthorized));
+ }) ;
+
+ $('#library_empty').show();
+ */
+ }
+ };
+
+ //
+ self._fetchData = function ( sSource, aoData, fnCallback, oSettings ) {
+
+ var echo = aoData[0].value; //Datatables state tracking. Must be included.
+
+ //getUsabilityHint();
+ var sortColName = "";
+ var sortDir = "";
+ if (oSettings.aaSorting.length > 0) {
+ var sortColIdx = oSettings.aaSorting[0][0];
+ sortColName = oSettings.aoColumns[sortColIdx].mDataProp;
+ sortDir = oSettings.aaSorting[0][1].toUpperCase();
+ }
+
+ $.ajax({
+ "dataType": 'json',
+ "type": "GET",
+ "url": sSource,
+ "data": {
+ "limit": oSettings._iDisplayLength,
+ "offset": oSettings._iDisplayStart,
+ "sort": sortColName,
+ 'sort_dir': sortDir,
+ },
+ "success": function (json, textStatus, jqXHR) {
+ var rawResponseJSON = json;
+ json = [];
+ json.aaData = rawResponseJSON;
+ json.iTotalRecords = jqXHR.getResponseHeader('X-TOTAL-COUNT');
+ json.iTotalDisplayRecords = json.iTotalRecords;//rawResponseJSON.length;
+ json.sEcho = echo;
+
+ //Pass it along to datatables.
+ fnCallback(json);
+ },
+ "error": self._handleAjaxError
+ }).done(function (data) {
+ /*
+ if (data.iTotalRecords > data.iTotalDisplayRecords) {
+ $('#filter_message').text(
+ $.i18n._("Filtering out ") + (data.iTotalRecords - data.iTotalDisplayRecords)
+ + $.i18n._(" of ") + data.iTotalRecords
+ + $.i18n._(" records")
+ );
+ $('#library_empty').hide();
+ $('#library_display').find('tr:has(td.dataTables_empty)').show();
+ } else {
+ $('#filter_message').text("");
+ }
+ $('#library_content').find('.dataTables_filter input[type="text"]')
+ .css('padding-right', $('#advanced-options').find('button').outerWidth());
+ */
+ });
+ };
+
+ self._datatablesCheckboxDataDelegate = function(rowData, callType, dataToSave) {
+
+
+ if (callType == undefined) {
+ //Supposed to return the raw data for the type here.
+ return null;
+ } else if (callType == 'display') {
+ return "";
+ } else if (callType == 'sort') {
+ return null;
+ } else if (callType == 'type') {
+ return "input";
+ } else if (callType == 'set') {
+ //The data to set is in dataToSave.
+ return;
+ } else if (callType == 'filter') {
+ return null;
+ }
+
+ //For all other calls, just return the data as this:
+ return "check";
+ };
+
+ self._rowCreatedCallback = function(nRow, aData, iDisplayIndex) {
+
+ // Bind click event
+ $(nRow).click(function(e) {
+ e.stopPropagation();
+ e.preventDefault();
+ document.getSelection().removeAllRanges();
+ //alert( 'You clicked on '+aData.track_title+'\'s row' + iDisplayIndex);
+ var selectionMode = self.SELECTION_MODE.SINGLE;
+ if (e.shiftKey) {
+ selectionMode = self.SELECTION_MODE.MULTI_SHIFT;
+ } else if (e.ctrlKey) {
+ selectionMode = self.SELECTION_MODE.MULTI_CTRL;
+ }
+ self.selectRow(nRow, aData, selectionMode, iDisplayIndex);
+ });
+
+ return nRow;
+ };
+
+ self._tableDrawCallback = function(oSettings) {
+
+ $('input.airtime_table_checkbox').click(function(e) {
+ $this = $(this);
+
+ var iVisualRowIdx = $this.parent().parent().index();
+ self.selectRow($this.parent().parent(), null, self.SELECTION_MODE.MULTI_CTRL, iVisualRowIdx); //Always multiselect for checkboxes
+ e.stopPropagation();
+ return true;
+ });
+ };
+
+ /** @param nRow is a tr DOM node (non-jQuery)
+ * @param aData is an array containing the raw data for the row. Can be null if you don't have it.
+ * @param selectionMode is an SELECT_MODE enum. Specify what selection mode you want to use for this action.
+ * @param iVisualRowIdx is an integer which corresponds to the index of the clicked row, as it appears to the user.
+ * eg. The 5th row in the table will have an iVisualRowIdx of 4 (0-based).
+ */
+ self.selectRow = function(nRow, aData, selectionMode, iVisualRowIdx) {
+
+ //Default to single item selection.
+ if (selectionMode == undefined) {
+ selectionMode = self.SELECTION_MODE.SINGLE;
+ }
+
+ var $nRow = $(nRow);
+
+ /*
+ var foundAtIdx = $.inArray(aData, self._selectedRows)
+
+ if (foundAtIdx >= 0 && self._selectedRows.length > 1) {
+ self._selectedRows.splice(foundAtIdx, 1);
+ $nRow.removeClass('selected');
+ $nRow.find('input.airtime_table_checkbox').attr('checked', false);
+ */
+ if (false) {
+ } else {
+ //Regular single left-click mode
+ if (selectionMode == self.SELECTION_MODE.SINGLE) {
+
+ self._clearSelection();
+
+ self._selectedRows.push(aData);
+ self._selectedRowVisualIdxMin = iVisualRowIdx;
+ self._selectedRowVisualIdxMax = iVisualRowIdx;
+ //self._selectedRowVisualIdxMap[iVisualRowIdx] = aData;
+
+ $nRow.addClass('selected');
+ $nRow.find('input.airtime_table_checkbox').attr('checked', true);
+ }
+ //Ctrl-click multi row selection mode
+ else if (selectionMode == self.SELECTION_MODE.MULTI_CTRL) {
+
+
+ var foundAtIdx = $.inArray(aData, self._selectedRows)
+ if (foundAtIdx >= 0 && self._selectedRows.length > 1) {
+ self._selectedRows.splice(foundAtIdx, 1);
+ $nRow.removeClass('selected');
+ $nRow.find('input.airtime_table_checkbox').attr('checked', false);
+ }
+ else {
+ self._selectedRows.push(aData);
+
+ self._selectedRowVisualIdxMin = iVisualRowIdx;
+ self._selectedRowVisualIdxMax = iVisualRowIdx;
+
+ $nRow.addClass('selected');
+ $nRow.find('input.airtime_table_checkbox').attr('checked', true);
+ }
+ }
+ //Shift-click multi row selection mode
+ else if (selectionMode == self.SELECTION_MODE.MULTI_SHIFT) {
+
+ //If there's no rows selected, just behave like single selection.
+ if (self._selectedRows.length == 0) {
+ return self.selectRow(nRow, aData, self.SELECTION_MODE.SINGLE, iVisualRowIdx);
+ }
+
+ if (iVisualRowIdx > self._selectedRowVisualIdxMax) {
+ self._selectedRowVisualIdxMax = iVisualRowIdx;
+ }
+ if (iVisualRowIdx < self._selectedRowVisualIdxMin) {
+ self._selectedRowVisualIdxMin = iVisualRowIdx;
+ }
+
+ var selectionStartRowIdx = Math.min(iVisualRowIdx, self._selectedRowVisualIdxMin);
+ var selectionEndRowIdx = Math.min(iVisualRowIdx, self._selectedRowVisualIdxMax);
+
+
+ //We can assume there's at least 1 row already selected now.
+ var allRows = self._datatable.fnGetData();
+
+ self._selectedRows = [];
+ for (var i = self._selectedRowVisualIdxMin; i <= self._selectedRowVisualIdxMax; i++)
+ {
+ self._selectedRows.push(allRows[i]);
+ $row = $($nRow.parent().children()[i]);
+ $row.addClass('selected');
+ $row.find('input.airtime_table_checkbox').attr('checked', true);
+ }
+
+ }
+ else {
+ console.log("Unimplemented selection mode");
+ }
+ }
+ };
+
+ self._clearSelection = function() {
+ self._selectedRows = [];
+ //self._selectedRowVisualIdxMap = [];
+ self._selectedRowVisualIdxMin = self.HUGE_INT;
+ self._selectedRowVisualIdxMax = -1;
+ self._$wrapperDOMNode.find('.selected').removeClass('selected');
+ self._$wrapperDOMNode.find('input.airtime_table_checkbox').attr('checked', false);
+ };
+
+ self.getSelectedRows = function() {
+ return self._selectedRows;
+ }
+
+ return AIRTIME;
+
+}(AIRTIME || {}));
+
+