'; //dialog div
- //r+= '
'; //reset button and its div
- r += divRowDef;
-
- for (j = 0; j < iLen; j++) {
-
- //if last check close div
- if (j % numRow == 0 && j != 0) {
- r += divClose + divRowDef;
- }
-
- var sLabel = aData[j];
- var sValue = aData[j];
-
- if (typeof (aData[j]) == 'object') {
- sLabel = aData[j].label;
- sValue = aData[j].value;
- }
-
- //check button
- r += '
' + sLabel + '
';
-
- var checkbox = $(r);
- th.html(checkbox);
- th.wrapInner('
');
- //on every checkbox selection
- checkbox.change(function () {
-
- var search = '';
- var or = '|'; //var for select checks in 'or' into the regex
- var resSize = $('input:checkbox[name="' + localLabel + '"]:checked').size();
- $('input:checkbox[name="' + localLabel + '"]:checked').each(function (index) {
-
- //search = search + ' ' + $(this).val();
- //concatenation for selected checks in or
- if ((index == 0 && resSize == 1)
- || (index != 0 && index == resSize - 1)) {
- or = '';
- }
- //trim
- search = search.replace(/^\s+|\s+$/g, "");
- search = search + $(this).val() + or;
- or = '|';
-
- });
-
-
- if (search != "") {
- $('input:checkbox[name="' + localLabel + '"]').removeClass("search_init");
- } else {
- $('input:checkbox[name="' + localLabel + '"]').addClass("search_init");
- }
- /* Old code for setting search_init CSS class on checkboxes if any of them is checked
- for (var jj = 0; jj < iLen; jj++) {
- if (search != "") {
- $('#' + aData[jj]).removeClass("search_init");
- } else {
- $('#' + aData[jj]).addClass("search_init");
- }
- }
- */
-
- //execute search
- oTable.fnFilter(search, index, true, false);
- fnOnFiltered();
- });
- }
-
- //filter button
- $('#' + buttonId).button();
- //dialog
- $('#' + checkToggleDiv).dialog({
- //height: 140,
- autoOpen: false,
- //show: "blind",
- hide: "blind",
- buttons: [{
- text: "Reset",
- click: function () {
- //$('#'+buttonId).removeClass("filter_selected"); //LM remove border if filter selected
- $('input:checkbox[name="' + localLabel + '"]:checked').each(function (index3) {
- $(this).attr('checked', false);
- $(this).addClass("search_init");
- });
- oTable.fnFilter('', index, true, false);
- fnOnFiltered();
- return false;
- }
- },
- {
- text: "Close",
- click: function () { $(this).dialog("close"); }
- }
- ]
- });
-
-
- $('#' + buttonId).click(function () {
-
- $('#' + checkToggleDiv).dialog('open');
- var target = $(this);
- $('#' + checkToggleDiv).dialog("widget").position({ my: 'top',
- at: 'bottom',
- of: target
- });
-
- return false;
- });
-
- var fnOnFilteredCurrent = fnOnFiltered;
-
- fnOnFiltered = function () {
- var target = $('#' + buttonId);
- $('#' + checkToggleDiv).dialog("widget").position({ my: 'top',
- at: 'bottom',
- of: target
- });
- fnOnFilteredCurrent();
- };
- //reset
- /*
- $('#'+buttonId+"Reset").button();
- $('#'+buttonId+"Reset").click(function(){
- $('#'+buttonId).removeClass("filter_selected"); //LM remove border if filter selected
- $('input:checkbox[name="'+localLabel+'"]:checked').each(function(index3) {
- $(this).attr('checked', false);
- $(this).addClass("search_init");
- });
- oTable.fnFilter('', index, true, false);
- return false;
- });
- */
- }
-
-
-
-
- function _fnRangeLabelPart(iPlace) {
- switch (iPlace) {
- case 0:
- return sRangeFormat.substring(0, sRangeFormat.indexOf("{from}"));
- case 1:
- return sRangeFormat.substring(sRangeFormat.indexOf("{from}") + 6, sRangeFormat.indexOf("{to}"));
- default:
- return sRangeFormat.substring(sRangeFormat.indexOf("{to}") + 4);
- }
- }
-
-
-
-
- var oTable = this;
-
- var defaults = {
- sPlaceHolder: "foot",
- sRangeSeparator: "~",
- iFilteringDelay: 500,
- aoColumns: null,
- sRangeFormat: "From {from} to {to}",
- sDateFromToken: "from",
- sDateToToken: "to"
- };
-
- var properties = $.extend(defaults, options);
-
- return this.each(function () {
-
- if (!oTable.fnSettings().oFeatures.bFilter)
- return;
- asInitVals = new Array();
-
- var aoFilterCells = oTable.fnSettings().aoFooter[0];
-
- var oHost = oTable.fnSettings().nTFoot; //Before fix for ColVis
- var sFilterRow = "tr"; //Before fix for ColVis
-
- if (properties.sPlaceHolder == "head:after") {
- var tr = $("tr:first", oTable.fnSettings().nTHead).detach();
- //tr.appendTo($(oTable.fnSettings().nTHead));
- if (oTable.fnSettings().bSortCellsTop) {
- tr.prependTo($(oTable.fnSettings().nTHead));
- //tr.appendTo($("thead", oTable));
- aoFilterCells = oTable.fnSettings().aoHeader[1];
- }
- else {
- tr.appendTo($(oTable.fnSettings().nTHead));
- //tr.prependTo($("thead", oTable));
- aoFilterCells = oTable.fnSettings().aoHeader[0];
- }
-
- sFilterRow = "tr:last";
- oHost = oTable.fnSettings().nTHead;
-
- } else if (properties.sPlaceHolder == "head:before") {
-
- if (oTable.fnSettings().bSortCellsTop) {
- var tr = $("tr:first", oTable.fnSettings().nTHead).detach();
- tr.appendTo($(oTable.fnSettings().nTHead));
- aoFilterCells = oTable.fnSettings().aoHeader[1];
- } else {
- aoFilterCells = oTable.fnSettings().aoHeader[0];
- }
- /*else {
- //tr.prependTo($("thead", oTable));
- sFilterRow = "tr:first";
- }*/
-
- sFilterRow = "tr:first";
-
- oHost = oTable.fnSettings().nTHead;
-
-
- }
-
- //$(sFilterRow + " th", oHost).each(function (index) {//bug with ColVis
- $(aoFilterCells).each(function (index) {//fix for ColVis
- i = index;
- var aoColumn = { type: "text",
- bRegex: false,
- bSmart: true,
- iMaxLenght: -1,
- iFilterLength: 0
- };
- if (properties.aoColumns != null) {
- if (properties.aoColumns.length < i || properties.aoColumns[i] == null)
- return;
- aoColumn = properties.aoColumns[i];
- }
- //label = $(this).text(); //Before fix for ColVis
- label = $($(this)[0].cell).text(); //Fix for ColVis
- if (aoColumn.sSelector == null) {
- //th = $($(this)[0]);//Before fix for ColVis
- th = $($(this)[0].cell); //Fix for ColVis
- }
- else {
- th = $(aoColumn.sSelector);
- if (th.length == 0)
- th = $($(this)[0].cell);
- }
-
- if (aoColumn != null) {
- if (aoColumn.sRangeFormat != null)
- sRangeFormat = aoColumn.sRangeFormat;
- else
- sRangeFormat = properties.sRangeFormat;
- switch (aoColumn.type) {
- case "null":
- break;
- case "number":
- fnCreateInput(oTable, true, false, true, aoColumn.iFilterLength, aoColumn.iMaxLenght);
- break;
- case "select":
- if (aoColumn.bRegex != true)
- aoColumn.bRegex = false;
- fnCreateSelect(oTable, aoColumn.values, aoColumn.bRegex, aoColumn.selected, aoColumn.multiple);
- break;
- case "number-range":
- fnCreateRangeInput(oTable);
- break;
- case "date-range":
- fnCreateDateRangeInput(oTable);
- break;
- case "checkbox":
- fnCreateCheckbox(oTable, aoColumn.values);
- break;
- case "twitter-dropdown":
- case "dropdown":
- fnCreateDropdown(aoColumn.values);
- break;
- case "text":
- default:
- bRegex = (aoColumn.bRegex == null ? false : aoColumn.bRegex);
- bSmart = (aoColumn.bSmart == null ? false : aoColumn.bSmart);
- fnCreateInput(oTable, bRegex, bSmart, false, aoColumn.iFilterLength, aoColumn.iMaxLenght);
- break;
-
- }
- }
- });
-
- for (j = 0; j < aiCustomSearch_Indexes.length; j++) {
- //var index = aiCustomSearch_Indexes[j];
- var fnSearch_ = function () {
- var id = oTable.attr("id");
- return $("#" + id + "_range_from_" + aiCustomSearch_Indexes[j]).val() + properties.sRangeSeparator + $("#" + id + "_range_to_" + aiCustomSearch_Indexes[j]).val()
- }
- afnSearch_.push(fnSearch_);
- }
-
- if (oTable.fnSettings().oFeatures.bServerSide) {
-
- var fnServerDataOriginal = oTable.fnSettings().fnServerData;
-
- oTable.fnSettings().fnServerData = function (sSource, aoData, fnCallback) {
-
- for (j = 0; j < aiCustomSearch_Indexes.length; j++) {
- var index = aiCustomSearch_Indexes[j];
-
- for (k = 0; k < aoData.length; k++) {
- if (aoData[k].name == "sSearch_" + index)
- aoData[k].value = afnSearch_[j]();
- }
- }
- aoData.push({ "name": "sRangeSeparator", "value": properties.sRangeSeparator });
-
- if (fnServerDataOriginal != null) {
- try {
- fnServerDataOriginal(sSource, aoData, fnCallback, oTable.fnSettings()); //TODO: See Issue 18
- } catch (ex) {
- fnServerDataOriginal(sSource, aoData, fnCallback);
- }
- }
- else {
- $.getJSON(sSource, aoData, function (json) {
- fnCallback(json)
- });
- }
- };
-
- }
-
- });
-
- };
-
-
-
-
-})(jQuery);
\ No newline at end of file
diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css
index 776ece0..bd8d49c 100644
--- a/app/assets/stylesheets/application.css
+++ b/app/assets/stylesheets/application.css
@@ -11,9 +11,8 @@
* file per style scope.
*
*= require_tree .
- *= require dataTables/extras/dataTables.responsive
- *= require dataTables/jquery.dataTables
*= require select2
+ *= require datagrid
*= require_self
*= require purecss
*/
diff --git a/app/controllers/concerns/data_table.rb b/app/controllers/concerns/data_table.rb
deleted file mode 100644
index d961a0f..0000000
--- a/app/controllers/concerns/data_table.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-
-module DataTable
- extend ActiveSupport::Concern
-
- def apply_filter(user, params)
- params = sanitize_params(params)
- selection_to_json user, params[:draw], user.transactions
- .where(created_at: params[:columns][:time][:lower]..params[:columns][:time][:upper])
- .where("('debtor' = :id AND 'creditor' LIKE :peer) OR ('creditor' = :id AND 'debtor' LIKE :peer)", id: user.id, peer: "%#{params[:columns][:peer][:value]}%")
- .where("'issuer' LIKE :re", re: "%#{params[:columns][:issuer][:value]}%")
- .where("'message' LIKE :re", re: "%#{params[:columns][:message][:value]}%")
- # TODO: what about nil?
- end
-
- private
-
- def sanitize_params(params)
- # Parsing according to https://datatables.net/manual/server-side
- clean = {
- draw: params.require(:draw).to_i,
- start: params.require(:start).to_i,
- length: params.require(:length).to_i,
- columns: Hash.new
- }
- params.require(:columns).each do |i, column|
- type, value = column.require(:search)[:value].split(':')
- h = clean[:columns][column.require(:data).to_sym] = {
- name: column[:name],
- searchable: column[:searchable] == 'true',
- orderable: column[:orderable] == 'true',
- type: type
- }
- if type == 'number-range'
- h[:lower], h[:upper] = value.split('~').map &:to_i
- elsif type == 'date-range'
- h[:lower], h[:upper] = value.split('~').map &:to_datetime
- else
- h[:value] = value
- end
- end
- return clean
- end
-
- def selection_to_json(user, draw, selection)
- {
- draw: draw,
- recordsTotal: user.transactions.count,
- recordsFiltered: selection.count,
- data: selection.offset(params[:start]).take(params[:length]).map { |transaction| {
- time: transaction.created_at,
- amount: transaction.signed_amount_for(user),
- peer: transaction.peer_of(user).try(:name),
- issuer: transaction.issuer.name,
- message: transaction.message,
- }}
- }
- end
-end
-
diff --git a/app/controllers/transactions_controller.rb b/app/controllers/transactions_controller.rb
index 7b5626d..6042114 100644
--- a/app/controllers/transactions_controller.rb
+++ b/app/controllers/transactions_controller.rb
@@ -6,7 +6,9 @@ class TransactionsController < ApplicationController
before_action :authenticate_user_or_client!, only: :create
def index
- @transactions = Transaction.all
+ @grid = TransactionsGrid.new(params[:transactions_grid]) do |scope|
+ scope.page(params[:page])
+ end
end
def new
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 6dcaeb3..6fd3ae0 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -1,13 +1,10 @@
class UsersController < ApplicationController
load_and_authorize_resource
- include DataTable
-
def show
@user = User.find(params[:id])
respond_to do |format|
format.html
- format.json { render json: apply_filter(@user, params) }
end
end
diff --git a/app/grids/transactions_grid.rb b/app/grids/transactions_grid.rb
new file mode 100644
index 0000000..4a4d428
--- /dev/null
+++ b/app/grids/transactions_grid.rb
@@ -0,0 +1,17 @@
+class TransactionsGrid
+
+ include Datagrid
+
+ scope do
+ Transaction
+ end
+
+ filter(:id, :integer)
+ filter(:created_at, :date, range: true)
+
+ column(:id)
+ column(:amount)
+ column(:created_at) do |model|
+ model.created_at.to_date
+ end
+end
diff --git a/app/views/transactions/index.html.haml b/app/views/transactions/index.html.haml
index e69de29..c08d315 100644
--- a/app/views/transactions/index.html.haml
+++ b/app/views/transactions/index.html.haml
@@ -0,0 +1,4 @@
+= datagrid_form_for @grid, :method => :get, :url => transactions_path
+= paginate(@grid.assets)
+= datagrid_table @grid
+= paginate(@grid.assets)
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 288c694..5dc47d5 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -26,44 +26,3 @@
%td.input-listen{ 'data-input-type': 'text' }
%input{type: 'text', placeholder: 'Filter on Message'}
-:javascript
- $(document).ready(function() {
- var table = $('#transactions').DataTable({
- processing: true,
- serverSide: true,
- searching: false,
- lengthChange: false,
- ordering: false,
- ajax: $('#transactions').data('source'),
- pagingType: 'full_numbers',
- autoWidth: false,
- responsive: true,
- columns: [
- { data: 'time', name: 'Time', className: 'min-tablet-l'},
- { data: 'amount', name: 'Amount', className: 'min-mobile'},
- { data: 'peer', name: 'Peer', className: 'min-mobile'},
- { data: 'issuer', name: 'Issuer', className: 'min-desktop'},
- { data: 'message', name: 'Message', className: 'min-tablet-p'},
- ]
- });
-
- var tds = $('.input-listen');
- var i = 0;
- table.columns().every(function() {
- var column = this
- tds.eq(i).find('input').on('keyup change', function() {
- var value = null;
- var td = $(this).parent();
- if(td.hasClass('bound')) {
- value = td.find('.lower-bound').val() + '~' + td.find('.upper-bound').val();
- } else {
- value = $(this).val()
- }
- value = td.attr('data-input-type') + ':' + value
- if(column.search() !== value) {
- column.search(value).draw();
- }
- });
- i = i + 1;
- });
- });