From 7fd8abf381dcf7da8552687dd874b06454f3caab Mon Sep 17 00:00:00 2001 From: Julius Date: Tue, 16 Jul 2013 22:01:56 +0200 Subject: [PATCH] Replace 'own' js table sorting by stupidtable plugin --- app/assets/javascripts/application.js | 79 +------- app/assets/javascripts/stupidtable.js | 186 ++++++++++++++++++ app/views/deliveries/_form.html.haml | 10 +- .../_stock_article_for_adding.html.haml | 4 +- .../deliveries/_stock_change_fields.html.haml | 2 +- 5 files changed, 199 insertions(+), 82 deletions(-) create mode 100644 app/assets/javascripts/stupidtable.js diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 6c1a8626..26990b6c 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -11,6 +11,7 @@ //= require rails.validations //= require_self //= require ordering +//= require stupidtable // allow touch devices to work on click events // http://stackoverflow.com/a/16221066 @@ -25,34 +26,6 @@ $.fn.extend({ }()), }); -// function for sorting DOM elements -$.fn.sorter = (function(){ - // Thanks to James Padolsey and Avi Deitcher - // http://james.padolsey.com/javascript/sorting-elements-with-jquery/#comment-29400 - var sort = [].sort; - - return function(comparator, getSortable) { - getSortable = getSortable || function(){return this;}; - - var sorted = sort.call(this, comparator); // sort all elements in memory - var prevElmt = null; - for(i=sorted.length-1; i>=0; --i) { // loop starting from last - var criterionElmt = sorted[i]; - var curElmt = ( 'function' === typeof getSortable ) ? ( getSortable.call(criterionElmt) ) : ( criterionElmt ); - var parent = curElmt.parentNode; - if (!prevElmt) { - parent.appendChild(curElmt); // place last element to the end - } else { - parent.insertBefore(curElmt, prevElmt); // move each element before the previous one - } - prevElmt = curElmt; - } - return sorted; - - }; - -})(); - // Load following statements, when DOM is ready $(function() { @@ -144,53 +117,13 @@ $(function() { // Use bootstrap datepicker for dateinput $('.datepicker').datepicker({format: 'yyyy-mm-dd', language: I18n.locale}); - // Init table sorting - var myTriggerers = $('.dom-sort-triggerer'); - myTriggerers.wrapInner(''); - $('.dom-sort-link', myTriggerers).click(function(e) {sortTable(e); e.preventDefault();}); - // A title attribute ('sort ascending/descending') would be nice here. - // However, for a tiny detail like that it is not worth to translate everything: - // http://foodsoft.51229.x6.nabble.com/How-to-I18n-content-which-is-dynamically-loaded-via-javascript-assets-td75.html#a76 - - // Sort tables with a default sort - $('.dom-sort-link', '.default-sort').trigger('click'); + // See stupidtable.js for initialization of local table sorting }); -// compare two elements interpreted as text -function compareText(a, b) { - return $.trim(a.textContent).toLowerCase() < $.trim(b.textContent).toLowerCase() ? -1 : 1; -} - -// wrapper for $.fn.sorter (see above) for sorting tables -function sortTable(e) { - var sortLink = $(e.currentTarget); - - var sign = ( sortLink.hasClass('sortup') ) ? ( -1 ) : ( 1 ); - - var options = sortLink.closest('.dom-sort-triggerer').data(); - var sortCriterion = options.sortCriterion; // class name of (usually td) elements which define the order - var compareFunction = options.compareFunction; // function to compare two element contents for ordering - var sortElement = options.sortElement; // name of function which returns the movable element (default: 'thisParent') - var myTable = sortLink.closest('table'); // table to sort - - sortElement = ( 'undefined' === typeof sortElement ) ? ( function() {return this.parentNode;} ) : ( window[sortElement] ); // is this dirty? - - $('.' + sortCriterion, myTable).sorter( - function(a, b) { - return sign*window[compareFunction](a, b); // again dirty? - }, - sortElement - ); - - $('.dom-sort-link', myTable).removeClass('sortup sortdown'); - sortLink.addClass( - ( sign == 1 ) ? ( 'sortup' ) : ( 'sortdown' ) - ); -} - -// retrigger last sort function for elements in a context (e.g. after DOM update) -function updateSort(context) { - $('.sortup, .sortdown', context).toggleClass('sortup sortdown').trigger('click'); +// retrigger last local table sorting +function updateSort(table) { + $('.sorting-asc, .sorting-desc', table).toggleClass('.sorting-asc .sorting-desc') + .removeData('sort-dir').trigger('click'); // CAUTION: removing data field of plugin } // gives the row an yellow background diff --git a/app/assets/javascripts/stupidtable.js b/app/assets/javascripts/stupidtable.js new file mode 100644 index 00000000..4fe62acb --- /dev/null +++ b/app/assets/javascripts/stupidtable.js @@ -0,0 +1,186 @@ +// Stupid jQuery table plugin. + +// Call on a table +// sortFns: Sort functions for your datatypes. +(function($) { + + $.fn.stupidtable = function(sortFns) { + return this.each(function() { + var $table = $(this); + sortFns = sortFns || {}; + + // ==================================================== // + // Utility functions // + // ==================================================== // + + // Merge sort functions with some default sort functions. + sortFns = $.extend({}, { + "int": function(a, b) { + return parseInt(a, 10) - parseInt(b, 10); + }, + "float": function(a, b) { + return parseFloat(a) - parseFloat(b); + }, + "string": function(a, b) { + if (a < b) return -1; + if (a > b) return +1; + return 0; + }, + "string-ins": function(a, b) { + a = a.toLowerCase(); + b = b.toLowerCase(); + if (a < b) return -1; + if (a > b) return +1; + return 0; + } + }, sortFns); + + // Return the resulting indexes of a sort so we can apply + // this result elsewhere. This returns an array of index numbers. + // return[0] = x means "arr's 0th element is now at x" + var sort_map = function(arr, sort_function, reverse_column) { + var map = []; + var index = 0; + if (reverse_column) { + for (var i = arr.length-1; i >= 0; i--) { + map.push(i); + } + } + else { + var sorted = arr.slice(0).sort(sort_function); + for (var i=0; i'); + $('.stupidlink', stupidtables).on('click', function(e) {e.preventDefault();}); + + // Init stupidtable sorting + stupidtables.stupidtable(); + + // Update class of sort link after sort to match foodsoft style + stupidtables.on('aftertablesort', function(e, data) { + // Ignore data and use the updated classes in DOM + var stupidthead = $('thead', this); + $('a.stupidlink', stupidthead).removeClass('sortup sortdown'); + $('th.sorting-asc a.stupidlink', stupidthead).addClass('sortup'); + $('th.sorting-desc a.stupidlink', stupidthead).addClass('sortdown'); + }); + + // Sort tables with a default sort + $('.default-sort', stupidtables).trigger('click'); + } +}); diff --git a/app/views/deliveries/_form.html.haml b/app/views/deliveries/_form.html.haml index 52e7a799..c1702708 100644 --- a/app/views/deliveries/_form.html.haml +++ b/app/views/deliveries/_form.html.haml @@ -94,11 +94,10 @@ = f.association :supplier, :as => :hidden %h2= t '.title_select_stock_articles' - %table.table.table-hover#stock_articles_for_adding + %table#stock_articles_for_adding.table.table-hover.stupidtable %thead %tr - %th.dom-sort-triggerer.default-sort{:data => {'compare-function' => 'compareText', 'sort-criterion' => 'sort-by-name'}} - = t '.article' + %th.default-sort{:data => {:sort => 'string'}}= t '.article' %th= t '.price' %th= t '.unit' %th= t '.category' @@ -115,11 +114,10 @@ = render :partial => 'stock_article_for_adding', :locals => {:article => article} %h2= t '.title_fill_quantities' - %table.table#stock_changes + %table.table#stock_changes.stupidtable %thead %tr - %th.dom-sort-triggerer.default-sort{:data => {'compare-function' => 'compareText', 'sort-criterion' => 'sort-by-name'}} - = t '.article' + %th.default-sort{:data => {:sort => 'string'}}= t '.article' %th= t '.price' %th= t '.unit' %th= t '.quantity' diff --git a/app/views/deliveries/_stock_article_for_adding.html.haml b/app/views/deliveries/_stock_article_for_adding.html.haml index 964dea2f..b43df782 100644 --- a/app/views/deliveries/_stock_article_for_adding.html.haml +++ b/app/views/deliveries/_stock_article_for_adding.html.haml @@ -1,9 +1,9 @@ - css_class = ( @delivery and @delivery.includes_article? article ) ? ( 'unavailable' ) : ( false ) %tr{:id => "stock_article_#{article.id}", :class => css_class} - %td.sort-by-name= article.name + %td= article.name %td{:data => {:toggle => :tooltip, :title => render(:partial => 'shared/article_price_info', :locals => {:article => article})}}= number_to_currency article.price %td= article.unit - %td.sort-by-category= article.article_category.name + %td= article.article_category.name %td = link_to t('.action_edit'), edit_stock_article_supplier_deliveries_path(@supplier, :stock_article_id => article.id), remote: true, class: 'btn btn-mini' = link_to t('.action_other_price'), copy_stock_article_supplier_deliveries_path(@supplier, :old_stock_article_id => article.id), remote: true, class: 'btn btn-mini' diff --git a/app/views/deliveries/_stock_change_fields.html.haml b/app/views/deliveries/_stock_change_fields.html.haml index 000dd218..6ff19ac9 100644 --- a/app/views/deliveries/_stock_change_fields.html.haml +++ b/app/views/deliveries/_stock_change_fields.html.haml @@ -1,7 +1,7 @@ - stock_change = f.object - stock_article = stock_change.stock_article %tr{:id => "stock_change_stock_article_#{stock_article.id}", :data => {:id => stock_article.id}} - %td.sort-by-name + %td %span.stock_article_name= stock_change.stock_article.name = f.association :stock_article, :as => :hidden %td.price{:data => {:toggle => :tooltip, :title => render(:partial => 'shared/article_price_info', :locals => {:article => stock_article})}}= number_to_currency stock_article.price