diff options
author | Yorhel <git@yorhel.nl> | 2019-10-27 11:41:42 +0100 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2019-11-10 12:44:55 +0100 |
commit | 279c4c9f82b45863f91a16867e4830695de7e0ce (patch) | |
tree | 819685a29d3c421e68cccb45d56849592afe1c8e | |
parent | 9616e64115940ea0008ca5243c7085c40fe11013 (diff) |
ulist: Add some styling, sorting and a framework for extended info/options
-rw-r--r-- | data/style.css | 9 | ||||
-rw-r--r-- | elm/global.js | 25 | ||||
-rw-r--r-- | lib/VNWeb/User/Lists.pm | 102 |
3 files changed, 102 insertions, 34 deletions
diff --git a/data/style.css b/data/style.css index b48188aa..f1c0fd7e 100644 --- a/data/style.css +++ b/data/style.css @@ -789,6 +789,15 @@ div.votelist td.tc2 { width: 50px; text-align: right; padding-right: 10px } .labeledit select { width: 100% } .labeledit tfoot div { float: right; text-align: right } +.ulist .tc1 label { cursor: pointer } +.ulist .tc1 input { display: none } +.ulist .tc1 label:before { content: '▸ ' } +.ulist .tc1 input:checked + label:before { content: '▾ ' } +.ulist .tc1 { white-space: nowrap; width: 60px } +.ulist .tc2 b { margin-left: 10px } +.ulist .tc4 { white-space: nowrap; width: 60px; text-align: right; padding-right: 10px } +.ulist .tc5, .ulist .tc6, .ulist .tc7 { white-space: nowrap; width: 100px } + /***** User VN list browser ******/ diff --git a/elm/global.js b/elm/global.js index d396e0bc..367507c5 100644 --- a/elm/global.js +++ b/elm/global.js @@ -26,13 +26,34 @@ document.querySelectorAll('div[data-elm-module]').forEach(function(el) { }); -/* "check all" checkbox */ +/* "checkall" checkbox, usage: + * + * <input type="checkbox" class="checkall" name="$somename"> + * + * Checking that will synchronize all other checkboxes with name="$somename". + */ document.querySelectorAll('input[type=checkbox].checkall').forEach(function(el) { el.onclick = function() { document.querySelectorAll('input[type=checkbox][name="'+el.name+'"]').forEach(function(el2) { if(!el2.classList.contains('hidden')) { - el2.checked = el.checked; + if(el2.checked != el.checked) + el2.click(); } }); }; }); + + +/* "checkhidden" checkbox, usage: + * + * <input type="checkbox" class="checkhidden" value="$somename"> + * + * Checking that will toggle the 'hidden' class of all elements with the "$somename" class. + */ +document.querySelectorAll('input[type=checkbox].checkhidden').forEach(function(el) { + el.onclick = function() { + document.querySelectorAll('.'+el.value).forEach(function(el2) { + el2.classList.toggle('hidden', !el.checked); + }); + }; +}); diff --git a/lib/VNWeb/User/Lists.pm b/lib/VNWeb/User/Lists.pm index 482eca04..e29985fc 100644 --- a/lib/VNWeb/User/Lists.pm +++ b/lib/VNWeb/User/Lists.pm @@ -23,8 +23,10 @@ sub filters_ { my $opt = eval { tuwf->validate(get => p => { upage => 1 }, - l => { type => 'array', scalar => 1, required => 0, default => [], values => { id => 1 } } - )->data } || { p => 1, l => [] }; + l => { type => 'array', scalar => 1, required => 0, default => [], values => { id => 1 } }, + s => { required => 0, default => 'title', enum => [qw[ title vote added started finished ]] }, + o => { required => 0, default => 'a', enum => ['a', 'd'] }, + )->data } || { p => 1, l => [], s => 'title', o => 'a' }; # $labels only includes labels we are allowed to see, getting rid of any labels in 'l' that aren't in $labels ensures we only filter on visible labels my %accessible_labels = map +($_->{id}, 1), @$labels; @@ -65,6 +67,42 @@ sub filters_ { } +sub vn_ { + my($n, $v, $labels) = @_; + tr_ mkclass(odd => $n % 2 == 0), sub { + td_ class => 'tc1', sub { + input_ type => 'checkbox', class => 'checkhidden', name => 'collapse_vid', id => 'collapse_vid'.$v->{id}, value => 'collapsed_vid'.$v->{id}; + label_ for => 'collapse_vid'.$v->{id}, sub { + my $obtained = grep $_->{status} == 2, $v->{rels}->@*; + my $total = $v->{rels}->@*; + my $txt = sprintf '%d/%d', $obtained, $total; + if($total && $obtained == $total) { b_ class => 'done', $txt } + elsif($obtained < $total) { b_ class => 'todo', $txt } + else { txt_ $txt } + }; + }; + td_ class => 'tc2', sub { + a_ href => "/v$v->{id}", title => $v->{original}||$v->{title}, shorten $v->{title}, 70; + b_ class => 'grayedout', $v->{notes} if $v->{notes}; + }; + td_ class => 'tc3', sub { + my %l = map +($_,1), $v->{labels}->@*; + my @l = grep $l{$_->{id}} && $_->{id} != 7, @$labels; + join_ ', ', sub { txt_ $_->{label} }, @l if @l; + txt_ '-' if !@l; + }; + td_ class => 'tc4', fmtvote $v->{vote}; + td_ class => 'tc5', fmtdate $v->{added}, 'compact'; + td_ class => 'tc6', $v->{started}||''; + td_ class => 'tc7', $v->{finished}||''; + }; + + tr_ mkclass(hidden => 1, 'collapsed_vid'.$v->{id} => 1, odd => $n % 2 == 0), sub { + td_ colspan => 7, 'Options, releases and note stuff here (likely Elm)'; + }; +} + + sub listing_ { my($uid, $own, $opt, $labels) = @_; @@ -83,50 +121,50 @@ sub listing_ { FROM ulists ul JOIN vn v ON v.id = ul.vid WHERE', $where, ' - ORDER BY v.title' + ORDER BY', { + title => 'v.title', + vote => 'ul.vote', + added => 'ul.added', + started => 'ul.started', + finished => 'ul.finished' + }->{$opt->{s}}, $opt->{o} eq 'd' ? 'DESC' : 'ASC', 'NULLS LAST, v.title' ); enrich_flatten labels => id => vid => sql('SELECT vid, lbl FROM ulists_vn_labels WHERE uid =', \$uid, 'AND vid IN'), $lst; + enrich rels => id => vid => sub { sql ' + SELECT rv.vid, r.id, r.title, r.original, r.released, r.type, rl.status + FROM rlists rl + JOIN releases r ON rl.rid = r.id + JOIN releases_vn rv ON rv.id = r.id + WHERE rl.uid =', \$uid, ' + AND rv.vid IN', $_, ' + ORDER BY r.released ASC' + }, $lst; + + enrich_flatten lang => id => id => sub { sql('SELECT id, lang FROM releases_lang WHERE id IN', $_, 'ORDER BY lang') }, map $_->{rels}, @$lst; + my sub url { '?'.query_encode %$opt, @_ } # TODO: In-line editable - # TODO: Sorting # TODO: Releases - # TODO: Styling # TODO: Thumbnail view paginate_ \&url, $opt->{p}, [ $count, 50 ], 't'; div_ class => 'mainbox browse ulist', sub { - table_ class => 'stripe', sub { + table_ sub { thead_ sub { tr_ sub { - td_ class => 'tc1', sub { txt_ '▸'; debug_ $lst }; - td_ class => 'tc2', 'Title'; + td_ class => 'tc1', sub { + input_ type => 'checkbox', class => 'checkall', name => 'collapse_vid', id => 'collapse_vid'; + label_ for => 'collapse_vid', sub { txt_ 'Opt' }; + }; + td_ class => 'tc2', sub { txt_ 'Title'; sortable_ 'title', $opt, \&url; debug_ $lst }; td_ class => 'tc3', 'Labels'; - td_ class => 'tc4', 'Vote'; - td_ class => 'tc5', 'Added'; - td_ class => 'tc6', 'Start date'; - td_ class => 'tc7', 'End date'; - td_ class => 'tc8', 'Options'; + td_ class => 'tc4', sub { txt_ 'Vote'; sortable_ 'vote', $opt, \&url }; + td_ class => 'tc5', sub { txt_ 'Added'; sortable_ 'added', $opt, \&url }; + td_ class => 'tc6', sub { txt_ 'Start date'; sortable_ 'started', $opt, \&url }; + td_ class => 'tc7', sub { txt_ 'End date'; sortable_ 'finished', $opt, \&url }; }}; - tr_ sub { - my $v = $_; - td_ class => 'tc1', '▸ 0/0'; - td_ class => 'tc2', sub { - a_ href => "/v$v->{id}", title => $v->{original}||$v->{title}, shorten $v->{title}, 70; - b_ class => 'grayedout', $v->{notes} if $v->{notes}; - }; - td_ class => 'tc3', sub { - my %l = map +($_,1), $v->{labels}->@*; - my @l = grep $l{$_->{id}} && $_->{id} != 7, @$labels; - join_ ', ', sub { txt_ $_->{label} }, @l if @l; - txt_ '-' if !@l; - }; - td_ class => 'tc4', fmtvote $v->{vote}; - td_ class => 'tc5', fmtdate $v->{added}, 'compact'; - td_ class => 'tc6', $v->{started}||''; - td_ class => 'tc7', $v->{finished}||''; - td_ class => 'tc8', ''; - } for @$lst; + vn_ $_, $lst->[$_], $labels for (0..$#$lst); }; }; paginate_ \&url, $opt->{p}, [ $count, 50 ], 'b'; |