diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,10 @@ *~ /vendor/plugins/rails_upgrade + +#ignore public assets??? +/public/assets + +#ignore .orig and .swp +*.orig +*.swp diff --git a/Gemfile b/Gemfile --- a/Gemfile +++ b/Gemfile @@ -37,9 +37,11 @@ # gem 'debugger' # +# jquery addition gem 'jquery-rails' gem 'jquery-ui-sass-rails' gem 'jquery-timepicker-addon-rails' +gem 'jquery-tablesorter' #syntax highlighter gem 'rouge' diff --git a/Gemfile.lock b/Gemfile.lock --- a/Gemfile.lock +++ b/Gemfile.lock @@ -58,6 +58,8 @@ jquery-rails (3.1.1) railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) + jquery-tablesorter (1.12.7) + railties (>= 3.1, < 5) jquery-timepicker-addon-rails (1.4.1) railties (>= 3.1) jquery-ui-rails (4.0.3) @@ -152,6 +154,7 @@ haml in_place_editing jquery-rails + jquery-tablesorter jquery-timepicker-addon-rails jquery-ui-sass-rails mail diff --git a/app/assets/javascripts/new.js b/app/assets/javascripts/new.js --- a/app/assets/javascripts/new.js +++ b/app/assets/javascripts/new.js @@ -4,3 +4,4 @@ //= require jquery.ui.datepicker //= require jquery.ui.slider //= require jquery-ui-timepicker-addon +//= require jquery-tablesorter diff --git a/app/assets/stylesheets/application.css.sass b/app/assets/stylesheets/application.css.sass --- a/app/assets/stylesheets/application.css.sass +++ b/app/assets/stylesheets/application.css.sass @@ -4,7 +4,8 @@ @import jquery.ui.datepicker @import jquery.ui.slider @import jquery-ui-timepicker-addon - +@import jquery-tablesorter/theme.metro-dark +@import tablesorter-theme.cafe body background: white image-url("topbg.jpg") repeat-x top center diff --git a/app/assets/stylesheets/tablesorter-theme.cafe.css b/app/assets/stylesheets/tablesorter-theme.cafe.css new file mode 100644 --- /dev/null +++ b/app/assets/stylesheets/tablesorter-theme.cafe.css @@ -0,0 +1,197 @@ +/************* +Metro Dark Theme +*************/ +/* overall */ +.tablesorter-cafe { + // font: 12px/18px 'Segoe UI Semilight', 'Open Sans', Verdana, Arial, Helvetica, sans-serif; + color: #000; + background-color: #777; + margin: 10px 0 15px; + text-align: left; + border-collapse: collapse; + border: #555 1px solid; +} + +.tablesorter-cafe tr.dark-row th, .tablesorter-cafe tr.dark-row td { + background-color: #222; + color: #fff; + text-align: left; + font-size: 14px; +} + +/* header/footer */ +.tablesorter-cafe caption, +.tablesorter-cafe th, +.tablesorter-cafe thead td, +.tablesorter-cafe tfoot th, +.tablesorter-cafe tfoot td { + //font-weight: 300; + //font-size: 15px; + color: #fff; + background-color: #777; + padding: 2px; + border: #555 1px solid; +} + +.tablesorter-cafe .header, +.tablesorter-cafe .tablesorter-header { + background-image: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAGFBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u5jNePWAAAACHRSTlMAMxIHKwEgMWD59H4AAABSSURBVAjXY2BgYFJgAAHzYhDJ6igSAKTYBAUTgJSioKAQAwNzoaCguAFDiCAQuDIkgigxBgiA8cJAVCpQt6AgSL+JoKAzA0gjUBsQqBcBCYhFAAE/CV4zeSzxAAAAAElFTkSuQmCC); + background-position: center right; + background-repeat: no-repeat; + cursor: pointer; + white-space: normal; +} +.tablesorter-cafe .tablesorter-header-inner { + padding: 0 18px 0 4px; +} +.tablesorter-cafe thead .headerSortUp, +.tablesorter-cafe thead .tablesorter-headerSortUp, +.tablesorter-cafe thead .tablesorter-headerAsc { + background-image: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u5meJAOAAAACnRSTlMAMwsqXt+gIBUGxGoDMAAAAFlJREFUCNctzC0SQAAUReEzGNQ3AlHRiSRZFCVZYgeswRL8hLdK7834wj3tAlGP6y7fYHpKS6w6WwbVG0I1NZVnZPG8/DYxOYlnhUYkA06R1s9ESsxR4NIdPhkPFDFYuEnMAAAAAElFTkSuQmCC); +} +.tablesorter-cafe thead .headerSortDown, +.tablesorter-cafe thead .tablesorter-headerSortDown, +.tablesorter-cafe thead .tablesorter-headerDesc { + background-image: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAALVBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7i0NViAAAADnRSTlMAMiweCQITTvDctZZqaTlM310AAABcSURBVAjXY2BgYEtgAAFHERDJqigUAKSYBQUNgFSioKAYAwOLIBA4MASBKFUGQxAlzAAF+94BwWuGKBC1lIFl3rt3Lx0YGCzevWsGSjK9e6cAUlT3HKyW9wADAwDRrBiDy6bKzwAAAABJRU5ErkJggg==); +} +.tablesorter-cafe thead .sorter-false { + background-image: none; + cursor: default; + padding: 4px; +} + +/* tbody */ +.tablesorter-cafe td { + background-color: #fff; + padding: 1px 4px; + vertical-align: top; + border-style: solid; + border-color: #666; + border-collapse: collapse; + border-width: 0px 1px; + +} + +/* hovered row colors */ +.tablesorter-cafe tbody > tr:hover > td, +.tablesorter-cafe tbody > tr.even:hover > td, +.tablesorter-cafe tbody > tr.odd:hover > td { + background: #bbb; + color: #000; +} + +/* table processing indicator */ +.tablesorter-cafe .tablesorter-processing { + background-position: center center !important; + background-repeat: no-repeat !important; + /* background-image: url(../addons/pager/icons/loading.gif) !important; */ + background-image: url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=) !important; +} + +/* pager */ +.tablesorter-cafe .tablesorter-pager button { + background-color: #444; + color: #eee; + border: #555 1px solid; + cursor: pointer; +} +.tablesorter-cafe .tablesorter-pager button:hover { + background-color: #555; +} + +/* Zebra Widget - row alternating colors */ +.tablesorter-cafe tr.odd td { + background-color: #eee; +} +.tablesorter-cafe tr.even td { + background-color: #fff; +} + +/* Column Widget - column sort colors */ +.tablesorter-cafe tr.odd td.primary { + background-color: #bfbfbf; +} +.tablesorter-cafe td.primary, +.tablesorter-cafe tr.even td.primary { + background-color: #d9d9d9; +} +.tablesorter-cafe tr.odd td.secondary { + background-color: #d9d9d9; +} +.tablesorter-cafe td.secondary, +.tablesorter-cafe tr.even td.secondary { + background-color: #e6e6e6; +} +.tablesorter-cafe tr.odd td.tertiary { + background-color: #e6e6e6; +} +.tablesorter-cafe td.tertiary, +.tablesorter-cafe tr.even td.tertiary { + background-color: #f2f2f2; +} + +/* filter widget */ +.tablesorter-cafe .tablesorter-filter-row td { + background: #eee; + line-height: normal; + text-align: center; /* center the input */ + -webkit-transition: line-height 0.1s ease; + -moz-transition: line-height 0.1s ease; + -o-transition: line-height 0.1s ease; + transition: line-height 0.1s ease; +} +/* optional disabled input styling */ +.tablesorter-cafe .tablesorter-filter-row .disabled { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: not-allowed; +} +/* hidden filter row */ +.tablesorter-cafe .tablesorter-filter-row.hideme td { + /*** *********************************************** ***/ + /*** change this padding to modify the thickness ***/ + /*** of the closed filter row (height = padding x 2) ***/ + padding: 2px; + /*** *********************************************** ***/ + margin: 0; + line-height: 0; + cursor: pointer; +} +.tablesorter-cafe .tablesorter-filter-row.hideme .tablesorter-filter { + height: 1px; + min-height: 0; + border: 0; + padding: 0; + margin: 0; + /* don't use visibility: hidden because it disables tabbing */ + opacity: 0; + filter: alpha(opacity=0); +} +/* filters */ +.tablesorter-cafe .tablesorter-filter { + width: 95%; + height: auto; + margin: 4px; + padding: 4px; + background-color: #fff; + border: 1px solid #bbb; + color: #333; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: height 0.1s ease; + -moz-transition: height 0.1s ease; + -o-transition: height 0.1s ease; + transition: height 0.1s ease; +} +/* rows hidden by filtering (needed for child rows) */ +.tablesorter .filtered { + display: none; +} + +/* ajax error row */ +.tablesorter .tablesorter-errorRow td { + text-align: center; + cursor: pointer; + background-color: #e6bf99; +} diff --git a/app/controllers/user_admin_controller.rb b/app/controllers/user_admin_controller.rb --- a/app/controllers/user_admin_controller.rb +++ b/app/controllers/user_admin_controller.rb @@ -159,6 +159,8 @@ end @scorearray << ustat end + + render template: 'user_admin/user_stat' end def import diff --git a/app/views/report/login_stat.html.haml b/app/views/report/login_stat.html.haml --- a/app/views/report/login_stat.html.haml +++ b/app/views/report/login_stat.html.haml @@ -1,10 +1,12 @@ - content_for :header do + = stylesheet_link_tag 'tablesorter-theme.cafe' = javascript_include_tag 'new' %script{:type=>"text/javascript"} $(function () { $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} ); $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} ); + $('#my_table').tablesorter({widthFixed: true, widgets: ['zebra']}); }); %h1 Login status @@ -12,9 +14,9 @@ =render partial: 'report_menu' =render partial: 'date_range', locals: {param_text: 'Login date range:', title: 'Query login stat in the range' } -%table.info +%table.tablesorter-cafe#my_table %thead - %tr.info-head + %tr %th login %th full name %th login count @@ -27,5 +29,4 @@ %td= l[:full_name] %td= l[:count] %td= l[:min] ? l[:min].in_time_zone.strftime('%Y-%m-%d %H:%M') : '' - %td= l[:max] ? l[:max].in_time_zone.strftime('%Y-%m-%d %H:%M') : '' - + %td= l[:max] ? time_ago_in_words(l[:max].in_time_zone) + ' ago' : '' diff --git a/app/views/user_admin/user_stat.html.erb b/app/views/user_admin/user_stat.html.erb deleted file mode 100644 --- a/app/views/user_admin/user_stat.html.erb +++ /dev/null @@ -1,48 +0,0 @@ -
Latest scores
- -User | -Name | -Activated? | -Logged in | -Contest(s) | -<% @problems.each do |p| %> -<%= p.name %> | -<% end %> -Total | -Passed | -
---|---|---|---|---|---|---|---|
<%= sc[i].login %> | -<%= sc[i].full_name %> | -<%= sc[i].activated %> | -- <%= sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no' %> - | -- <%= sc[i].contests.collect {|c| c.name}.join(', ') %> - | - <% else %> -<%= sc[i][0] %> | - <% total += sc[i][0] %> - <% num_passed += 1 if sc[i][1] %> - <% end %> - <% end %> -<%= total %> | -<%= num_passed %> | -