Skip to content
Snippets Groups Projects
Commit 6b1d4ba4 authored by Andrej Ramašeuski's avatar Andrej Ramašeuski
Browse files

Initial commit

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 588 additions and 0 deletions
package RVVote;
use Mojo::Base 'Mojolicious';
# This method will run once at server start
sub startup {
my $self = shift;
# Load configuration from hash returned by "my_app.conf"
my $config = $self->plugin('Config');
# Router
my $r = $self->routes;
# Normal route to controller
$r->get('/')->to('RV#index');
$r->get('/api/members/')->to('RV#members');
$r->post('/api/calculate/')->to('evaluation#process');
}
1;
package RVVote::Controller::Evaluation;
use Mojo::Base 'Mojolicious::Controller';
use YAML;
sub process {
my $c = shift;
my @ballots = ();
my $r;
BALLOT:
foreach my $ballot ( @{ $c->req->json } ) {
my @choices = ();
my %count = ();
CHOICE:
foreach my $choice ( split /\W+/, $ballot->{value} ) {
next CHOICE if $choice !~ /\w/;
if ( ! $count{ $choice }++ ) {
push @choices, $choice;
}
}
next BALLOT if ! scalar @choices;
push @ballots, {
voter => $ballot->{voter},
choices => \@choices,
}
}
my $total = ( scalar @ballots );
my $half = $total / 2;
my @log;
$c->stash->{ballots} = \@ballots;
# primarni rozdeleni listku a pocitani celkoveho poctu
BALLOT:
foreach my $ballot ( @ballots ) {
my $choice = $ballot->{choices}[0];
push @{ $r->{ $choice }{ballots} }, $ballot;
CHOICE:
foreach $choice ( @{ $ballot->{choices} } ) {
$r->{ $choice }{votes}++;
$r->{ $choice }{ballots} //= [];
}
}
# oznacovani moznosti bez polovicni podpory
CHOICE:
foreach my $choice ( keys %{ $r } ) {
if ( $r->{$choice}{votes} < $half ) {
$r->{$choice}{unsupported} = 1;
}
}
push @log, {
title => "Počáteční rozdělení ($total listků)",
data => Dump $r,
};
# vyrazeni moznosti kteri nemaji nadpolovicni podporu
CHOICE:
foreach my $choice ( keys %{ $r } ) {
if ( $r->{$choice}{unsupported} ) {
$r = transfer($r, $choice);
}
}
push @log, {
title => 'Po vyřazení možnosti bez nadpoloviční podpory',
data => Dump $r,
};
my @winners = winners( $r, $half );
my $round = 1;
ROUND:
while ( ! scalar @winners && scalar keys %{ $r } > 1) {
my $random = 0;
my @loosers = loosers($r);
if ( scalar @loosers == scalar keys %{$r}) {
$random = 1;
@loosers = ( $loosers[ int(rand(scalar @loosers))]);
}
LOOSER:
foreach my $looser ( @loosers ) {
$r = transfer($r, $looser);
}
push @log, {
title => 'Vyřazovací kolo ' . $round++,
data => Dump $r,
loosers => \@loosers,
random => $random,
};
@winners = winners( $r, $half );
}
$c->stash->{log} = [ map {
{ title => $_->{title}, data => Load( $_->{data}) }
} @log ];
$c->stash->{winners} = \@winners;
$c->render( template => 'result' );
}
sub transfer {
my $r = shift;
my $choice = shift;
BALLOT:
foreach my $ballot ( @{ $r->{$choice}{ballots} } ) {
HEIR:
foreach my $heir ( @{ $ballot->{choices} } ) {
next HEIR if $heir eq $choice;
if ( exists $r->{ $heir } ) {
push @{ $r->{ $heir }{ballots} }, $ballot;
last HEIR;
}
}
}
delete $r->{ $choice };
return $r ;
}
sub choices_by_ballots {
my $r = shift;
return sort { scalar @{$r->{$b}{ballots}} <=> scalar @{$r->{$a}{ballots}} } keys %{ $r }
}
sub winners {
my $r = shift;
my $half = shift;
my @candidates = ();
my @winners = ();
CHOICE:
foreach my $choice ( choices_by_ballots( $r ) ) {
if ( scalar @{$r->{$choice}{ballots}} > $half ) {
push @candidates, $choice;
}
}
my $max = 0;
CANDIDATE:
foreach my $choice ( sort { $r->{$b}{votes} <=> $r->{$a}{votes} } @candidates ) {
$max ||= $r->{$choice}{votes};
push @winners, $choice if $r->{$choice}{votes} == $max;
}
return @winners;
}
sub loosers {
my $r = shift;
my @candidates = ();
my @loosers = ();
my $min = 0;
CHOICE:
foreach my $choice ( reverse choices_by_ballots( $r ) ) {
my $ballots = scalar @{$r->{$choice}{ballots}};
$min ||= $ballots;
push @candidates, $choice if scalar $ballots == $min;
}
$min = 0;
CANDIDATE:
foreach my $choice ( sort { $r->{$a}{votes} <=> $r->{$b}{votes} } @candidates ) {
$min ||= $r->{$choice}{votes};
push @loosers, $choice if $r->{$choice}{votes} == $min;
}
return @loosers;
}
1;
__END__
=cut
ROUND:
while ( 1 ) {
push @{ $c->stash->{log} }, {
title => $round++ . ". kolo" ,
data => { %{ $r } },
};
my ($min, $max, @loosers, $transfers);
CHOICE:
foreach my $choice ( keys %{ $r } ) {
my $count = scalar @{ $r->{$choice}{ballots} };
if ( ! defined $max || $count > $max ) {
$max = $count
}
if ( ! defined $min || $count < $min ) {
$min = $count;
@loosers = ($choice);
}
elsif ( defined $min && $count == $min ) {
push @loosers, $choice;
}
}
last ROUND if $max > $half;
my $looser = (sort { $r->{$a}{votes} <=> $r->{$b}{votes} } @loosers)[0];
push @{ $c->stash->{log} }, {
title => "Vyřazuje se možnost $looser",
};
my $transfer;
($transfer, $r) = transfer($r, $looser);
last ROUND if ! $transfer;
}
my $winner = (choices_by_ballots( $r ))[0];
=cut
package RVVote::Controller::RV;
use Mojo::Base 'Mojolicious::Controller';
use RVVote::GraphAPI;
sub index {
my $c = shift;
$c->render( template => 'rv_form' );
}
sub members {
my $c = shift;
my $gapi = RVVote::GraphAPI->new($c->config->{graph_api}{url});
my @members = $gapi->get_group_members($c->config->{graph_api}{rv_gid});
$c->render( json => \@members );
}
1;
package RVVote::GraphAPI;
use strict;
use warnings;
use utf8;
use Mojo::UserAgent;
our $VERSION = '0.01';
sub new {
my $classname = shift;
my $base_url = shift;
my $self = {};
$self->{ua} = Mojo::UserAgent->new();
$self->{base_url} = $base_url;
bless ($self, $classname);
return $self;
}
sub ua {
my $self = shift;
return $self->{ua};
}
sub get_group_members {
my $self = shift;
my $group_id = shift;
my $res = $self->ua->get( join '/', (
$self->{base_url},
$group_id,
'members'
))->result();
return undef if ! $res->is_success;
return undef if ! ref $res->json eq 'ARRAY';
my @members = ();
MEMBER:
foreach my $member ( @{ $res->json } ) {
my $res2 = $self->ua->get( join '/', (
$self->{base_url},
'user',
$member->{username_clean},
))->result();
next MEMBER if ! $res2->is_success;
next MEMBER if ! ref $res2->json eq 'ARRAY';
push @members, $res2->json;
}
return sort { $a->{fullname} le $b->{fullname} } @members;
};
/**
* bootstrap-table - An extended Bootstrap table with radio, checkbox, sort, pagination, and other added features. (supports twitter bootstrap v2 and v3).
*
* @version v1.14.2
* @homepage https://bootstrap-table.com
* @author wenzhixin <wenzhixin2010@gmail.com> (http://wenzhixin.net.cn/)
* @license MIT
*/
@charset "UTF-8";.bootstrap-table .fixed-table-toolbar:after{content:"";display:block;clear:both}.bootstrap-table .fixed-table-toolbar .bs-bars,.bootstrap-table .fixed-table-toolbar .search,.bootstrap-table .fixed-table-toolbar .columns{position:relative;margin-top:10px;margin-bottom:10px}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group{display:inline-block;margin-left:-1px!important}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group:first-child>.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group:last-child>.btn{border-top-right-radius:4px;border-bottom-right-radius:4px}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group>.btn{border-radius:0}.bootstrap-table .fixed-table-toolbar .columns .dropdown-menu{text-align:left;max-height:300px;overflow:auto}.bootstrap-table .fixed-table-toolbar .columns label{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429}.bootstrap-table .fixed-table-toolbar .columns-left{margin-right:5px}.bootstrap-table .fixed-table-toolbar .columns-right{margin-left:5px}.bootstrap-table .fixed-table-toolbar .pull-right .dropdown-menu{right:0;left:auto}.bootstrap-table .fixed-table-container{position:relative;clear:both}.bootstrap-table .fixed-table-container.fixed-height:not(.has-footer){border-bottom:1px solid #dee2e6}.bootstrap-table .fixed-table-container.fixed-height .fixed-table-border{border-left:1px solid #dee2e6;border-right:1px solid #dee2e6}.bootstrap-table .fixed-table-container.fixed-height .table thead th{border-bottom:1px solid #dee2e6}.bootstrap-table .fixed-table-container.fixed-height .table-dark thead th{border-bottom:1px solid #32383e}.bootstrap-table .fixed-table-container .fixed-table-header{overflow:hidden}.bootstrap-table .fixed-table-container .fixed-table-body{overflow-x:auto;overflow-y:auto;height:100%}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading{align-items:center;background:#fff;display:none;justify-content:center;position:absolute;bottom:0;width:100%;z-index:1000}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap{align-items:baseline;display:flex;justify-content:center}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .loading-text{font-size:2rem;margin-right:6px}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap{align-items:center;display:flex;justify-content:center}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-dot,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap:after,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap:before{content:"";animation-duration:1.5s;animation-iteration-count:infinite;animation-name:LOADING;background:#212529;border-radius:50%;display:block;height:5px;margin:0 4px;opacity:0;width:5px}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-dot{animation-delay:.3s}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap:after{animation-delay:.6s}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark{background:#212529}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-dot,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-wrap:after,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-wrap:before{background:#fff}.bootstrap-table .fixed-table-container .table{width:100%;margin-bottom:0!important}.bootstrap-table .fixed-table-container .table th,.bootstrap-table .fixed-table-container .table td{vertical-align:middle;box-sizing:border-box}.bootstrap-table .fixed-table-container .table thead th{vertical-align:bottom;padding:0;margin:0}.bootstrap-table .fixed-table-container .table thead th:focus{outline:0 solid transparent}.bootstrap-table .fixed-table-container .table thead th.detail{width:30px}.bootstrap-table .fixed-table-container .table thead th .th-inner{padding:.75rem;vertical-align:bottom;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bootstrap-table .fixed-table-container .table thead th .sortable{cursor:pointer;background-position:right;background-repeat:no-repeat;padding-right:30px}.bootstrap-table .fixed-table-container .table thead th .both{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7X QMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC")}.bootstrap-table .fixed-table-container .table thead th .asc{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBdqEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVoAADeemwtPcZI2wAAAABJRU5ErkJggg==")}.bootstrap-table .fixed-table-container .table thead th .desc{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWjYBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJzcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII= ")}.bootstrap-table .fixed-table-container .table tbody tr.selected td{background-color:rgba(0,0,0,0.075)}.bootstrap-table .fixed-table-container .table tbody tr.no-records-found{text-align:center}.bootstrap-table .fixed-table-container .table tbody tr .card-view .card-view-title{font-weight:bold;display:inline-block;min-width:30%;text-align:left!important}.bootstrap-table .fixed-table-container .table .bs-checkbox{text-align:center}.bootstrap-table .fixed-table-container .table input[type=radio],.bootstrap-table .fixed-table-container .table input[type=checkbox]{margin:0 auto!important}.bootstrap-table .fixed-table-container .table.table-sm .th-inner{padding:.3rem}.bootstrap-table .fixed-table-container .fixed-table-footer{overflow:hidden}.bootstrap-table .fixed-table-pagination:after{content:"";display:block;clear:both}.bootstrap-table .fixed-table-pagination>.pagination-detail,.bootstrap-table .fixed-table-pagination>.pagination{margin-top:10px;margin-bottom:10px}.bootstrap-table .fixed-table-pagination>.pagination-detail .pagination-info{line-height:34px;margin-right:5px}.bootstrap-table .fixed-table-pagination>.pagination-detail .page-list{display:inline-block}.bootstrap-table .fixed-table-pagination>.pagination-detail .page-list .btn-group{position:relative;display:inline-block;vertical-align:middle}.bootstrap-table .fixed-table-pagination>.pagination-detail .page-list .btn-group .dropdown-menu{margin-bottom:0}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination{margin:0}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination a{padding:6px 12px;line-height:1.428571429}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.page-intermediate a{color:#c8c8c8}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.page-intermediate a:before{content:"⬅"}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.page-intermediate a:after{content:"➡"}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.disabled a{pointer-events:none;cursor:default}.bootstrap-table.fullscreen{position:fixed;top:0;left:0;z-index:1050;width:100%!important;background:#FFF}div.fixed-table-scroll-inner{width:100%;height:200px}div.fixed-table-scroll-outer{top:0;left:0;visibility:hidden;width:200px;height:150px;overflow:hidden}@keyframes LOADING{0%{opacity:0}50%{opacity:1}to{opacity:0}}
\ No newline at end of file
This diff is collapsed.
/**
* bootstrap-table - An extended Bootstrap table with radio, checkbox, sort, pagination, and other added features. (supports twitter bootstrap v2 and v3).
*
* @version v1.14.2
* @homepage https://bootstrap-table.com
* @author wenzhixin <wenzhixin2010@gmail.com> (http://wenzhixin.net.cn/)
* @license MIT
*/
(function(a,b){if('function'==typeof define&&define.amd)define([],b);else if('undefined'!=typeof exports)b();else{b(),a.bootstrapTableCsCZ={exports:{}}.exports}})(this,function(){'use strict';(function(a){a.fn.bootstrapTable.locales['cs-CZ']={formatLoadingMessage:function(){return'\u010Cekejte, pros\xEDm'},formatRecordsPerPage:function(a){return a+' polo\u017Eek na str\xE1nku'},formatShowingRows:function(a,b,c){return'Zobrazena '+a+'. - '+b+'. polo\u017Eka z celkov\xFDch '+c},formatDetailPagination:function(a){return'Showing '+a+' rows'},formatSearch:function(){return'Vyhled\xE1v\xE1n\xED'},formatNoMatches:function(){return'Nenalezena \u017E\xE1dn\xE1 vyhovuj\xEDc\xED polo\u017Eka'},formatPaginationSwitch:function(){return'Skr\xFDt/Zobrazit str\xE1nkov\xE1n\xED'},formatRefresh:function(){return'Aktualizovat'},formatToggle:function(){return'P\u0159epni'},formatColumns:function(){return'Sloupce'},formatFullscreen:function(){return'Fullscreen'},formatAllRows:function(){return'V\u0161e'},formatAutoRefresh:function(){return'Auto Refresh'},formatExport:function(){return'Export data'},formatClearFilters:function(){return'Clear filters'},formatJumpto:function(){return'GO'},formatAdvancedSearch:function(){return'Advanced search'},formatAdvancedCloseButton:function(){return'Close'}},a.extend(a.fn.bootstrapTable.defaults,a.fn.bootstrapTable.locales['cs-CZ'])})(jQuery)});
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
body {
padding-top: 60px;
}
html {
font-size: .9rem;
}
@include media-breakpoint-up(sm) {
html {
font-size: .9rem;
}
}
@include media-breakpoint-up(md) {
html {
font-size: 1rem;
}
}
@include media-breakpoint-up(lg) {
html {
font-size: 1.2rem;
}
}
.btn-group {
margin: .2em 0;
}
.log {
margin-bottom .5em;
padding-bottom .5em;
}
{
secrets => ['ac605478557638569200e0e5333891c04929159a'],
graph_api => {
url => 'https://graph.pirati.cz',
rv_gid => 'deadbeef-babe-f002-000000000404',
}
}
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin;
BEGIN { unshift @INC, "$FindBin::Bin/../lib" }
use Mojolicious::Commands;
# Start command line interface for application
Mojolicious::Commands->start_app('RVVote');
use Mojo::Base -strict;
use Test::More;
use Test::Mojo;
my $t = Test::Mojo->new('RVVote');
$t->get_ok('/')->status_is(200)->content_like(qr/Mojolicious/i);
done_testing();
<div class="btn-group mr-2" role="group" aria-label="<%= $ballot->{voter} %>">
<button type="button" class="btn btn-secondary btn-sm"><%= $ballot->{voter} %></button>
% foreach my $choice ( @{ $ballot->{choices}} ) {
<button type="button" class="btn btn-outline-secondary btn-sm" disabled><%= $choice %></button>
% }
</div>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/bootstrap-table/bootstrap-table.min.css" rel="stylesheet">
<link href="/site.css" rel="stylesheet">
<script src="/jquery/jquery.min.js"></script>
<script src="/bootstrap/js/bootstrap.min.js"></script>
<script src="/bootstrap-table/bootstrap-table.min.js"></script>
<script src="/bootstrap-table/locale/bootstrap-table-cs-CZ.min.js"></script>
<title><%= title %></title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
<span class="navbar-brand"><%= title %></span>
</nav>
<div class="container">
<h2></h2>
<section>
<%= content %>
</section>
</div>
</body>
</html>
<div class="card bg-light log">
<div class="card-header"><h4><%= $log->{title} %></h4></div>
<div class="card-body">
% if ( $log->{loosers}) {
<div class="card bg-light border-light">
% foreach my $looser ( @{$log->{loosers}} ) {
<div class="card-header text-danger">Vyřazuje se <% if ($log->{random}) { %>(losováním) <%}%>možnost <%= $looser %></div>
% }
</div>
% }
% if ( $log->{data}) {
% foreach my $choice ( sort { scalar @{$log->{data}{$b}{ballots}} <=> scalar @{$log->{data}{$a}{ballots}} } keys %{ $log->{data} } ) {
<div class="card bg-light border-light">
<div class="card-header<%if ($log->{data}{$choice}{unsupported}) {%> text-danger<% } %>">
<strong>Volba "<%= $choice %>"</strong>
Počet listků: <%= scalar @{ $log->{data}{$choice}{ballots}}%>,
Počet hlásů: <%= $log->{data}{$choice}{votes} %>
% if ($log->{data}{$choice}{unsupported}) {
(nema nadpoloviční podporu)
% }
</div>
<div class="card-body">
% foreach my $ballot ( @{ $log->{data}{$choice}{ballots}} ) {
%= include 'layouts/ballot', ballot => $ballot
% }
</div>
</div>
% }
% }
</div><%# card-body %>
</div><%# card %>
<!--
% if (scalar @{ $c->stash->{ballots}} ) {
<div class="card bg-light">
<div class="card-header">Platné listky: <%= scalar @{$c->stash->{ballots}} %></div>
<div class="card-body">
<div class="card-text">
% foreach my $ballot ( @{ $c->stash->{ballots}} ) {
%= include 'layouts/ballot', ballot => $ballot
% }
</div>
</div>
</div>
% }
-->
% foreach my $log ( @{ $c->stash->{log}} ) {
%= include 'layouts/log', log => $log
% }
% if ( scalar @{ $c->stash->{winners}} ) {
<div class="alert alert-success" role="alert">
<h3>Je vybrána možnost <%= join ', ', @{ $c->stash->{winners}} %></h3>
</div>
% } else {
<div class="alert alert-danger" role="alert">
<h3>Není vybrána žádná možnost</h3>
</div>
% }
% layout 'default', title => 'Hlasovací kalkulačka RV';
<form>
<div class="container">
<div class="row">
<div class="col-5">
<table id="Members" data-toggle="table" data-url="/api/members/" data-sort-name="fullname" data-classes="table table-borderless table-sm" data-show-header="false">
<thead>
<tr>
<th data-field="fullname">Člen RV</th>
<th data-field="user_id" data-formatter="votes_detail" data-width="25%">Hlasy</th>
</tr>
</thead>
</table>
</div>
<div class="col-7" id="Result"></div>
</div>
</div>
<script>
function votes_detail(value, record) {
return '<input class="votes" name="votes_'+value+'" type="text" size="16" data-fullname="'+record.fullname+'">';
}
$('#Members').on('post-body.bs.table', function (data) {
$('input.votes').on('keyup', function () {
var bills = [];
var a = $('form').serializeArray();
$.each(a, function() {
var id = this.name.split('_');
bills.push({
"id": id[1],
"value": this.value,
"voter": $('input[name='+this.name+']').attr('data-fullname'),
});
});
$.ajax({
url: '/api/calculate/',
data: JSON.stringify(bills),
contentType: 'application/json',
type: "POST",
}).done(function( html ) {
$( "#Result" ).html( html );
})
});
});
</script>
</form>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment