Merge branch 'saas-dev-tablerefactor' into saas-dev-publishing
This commit is contained in:
commit
f6a33802db
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: asantoni
|
||||
* Date: 11/09/15
|
||||
* Time: 2:47 PM
|
||||
*/
|
||||
|
||||
class AirtimeTableView {
|
||||
|
||||
private static function _getTableJavaScriptDependencies() {
|
||||
return ['js/airtime/widgets/table.js',
|
||||
'js/datatables/js/jquery.dataTables.js',
|
||||
'js/datatables/plugin/dataTables.pluginAPI.js',
|
||||
'js/datatables/plugin/dataTables.fnSetFilteringDelay.js',
|
||||
'js/datatables/plugin/dataTables.ColVis.js',
|
||||
'js/datatables/plugin/dataTables.colReorder.min.js?',
|
||||
'js/datatables/plugin/dataTables.FixedColumns.js',
|
||||
'js/datatables/plugin/dataTables.FixedHeader.js',
|
||||
'js/datatables/plugin/dataTables.columnFilter.js?'];
|
||||
}
|
||||
|
||||
public static function injectTableJavaScriptDependencies(&$headScript, $baseUrl, $airtimeVersion)
|
||||
{
|
||||
$deps = self::_getTableJavaScriptDependencies();
|
||||
for ($i = 0; $i < count($deps); $i++) {
|
||||
$headScript->appendFile($baseUrl . $deps[$i] .'?'. $airtimeVersion, 'text/javascript');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
require_once(__DIR__.'/../common/widgets/Table.php');
|
||||
|
||||
class DashboardController extends Zend_Controller_Action
|
||||
{
|
||||
|
||||
|
@ -117,4 +119,17 @@ class DashboardController extends Zend_Controller_Action
|
|||
$this->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']);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<div class="text-content">
|
||||
<h2><?php echo _("Table Test") ?></h2>
|
||||
<p>
|
||||
Hello
|
||||
</p>
|
||||
<table id="example-table" cellpadding="0" cellspacing="0" class="datatable"></table>
|
||||
</div>
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
});
|
||||
});
|
|
@ -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 "<input type='checkbox' class='airtime_table_checkbox'>";
|
||||
} 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 || {}));
|
||||
|
||||
|
Loading…
Reference in New Issue